diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index 67a5b8a669b..5272d449e94 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -1221,6 +1221,24 @@ impl LowerTy for Ty { )?, }) .intern(interner)), + + Ty::Ref { + mutability, + lifetime, + ty, + } => Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { + name: chalk_ir::TypeName::Ref(ast_mutability_to_chalk_mutability( + mutability.clone(), + )), + substitution: chalk_ir::Substitution::from( + interner, + &[ + lifetime.lower(env)?.cast(interner), + ty.lower(env)?.cast(interner), + ], + ), + }) + .intern(interner)), } } } diff --git a/chalk-ir/src/debug.rs b/chalk-ir/src/debug.rs index 79b99656f9d..ed9b29c974b 100644 --- a/chalk-ir/src/debug.rs +++ b/chalk-ir/src/debug.rs @@ -145,6 +145,7 @@ impl Debug for TypeName { TypeName::Tuple(arity) => write!(fmt, "{:?}", arity), TypeName::OpaqueType(opaque_ty) => write!(fmt, "!{:?}", opaque_ty), TypeName::Raw(mutability) => write!(fmt, "{:?}", mutability), + TypeName::Ref(mutability) => write!(fmt, "{:?}", mutability), TypeName::Error => write!(fmt, "{{error}}"), } } diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index dd1c96c55dd..5b8dbc256c6 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -159,6 +159,9 @@ pub enum TypeName { /// a raw pointer type like `*const T` or `*mut T` Raw(Mutability), + /// a reference type like `&T` or `&mut T` + Ref(Mutability), + /// a placeholder for opaque types like `impl Trait` OpaqueType(OpaqueTyId), diff --git a/chalk-parse/src/ast.rs b/chalk-parse/src/ast.rs index 57bd8e34827..8dad563545e 100644 --- a/chalk-parse/src/ast.rs +++ b/chalk-parse/src/ast.rs @@ -197,6 +197,11 @@ pub enum Ty { mutability: Mutability, ty: Box, }, + Ref { + mutability: Mutability, + lifetime: Lifetime, + ty: Box, + }, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/chalk-parse/src/parser.lalrpop b/chalk-parse/src/parser.lalrpop index 86c8a555504..25ede469b52 100644 --- a/chalk-parse/src/parser.lalrpop +++ b/chalk-parse/src/parser.lalrpop @@ -205,7 +205,9 @@ TyWithoutFor: Ty = { "<" > ">" => Ty::Apply { name: n, args: a }, => Ty::Projection { proj: p }, "(" ")" => t, - "*" => Ty::Raw{ mutability: m, ty: Box::new(t) }, + "*" => Ty::Raw{ mutability: m, ty: Box::new(t) }, + "&" "mut" => Ty::Ref{ mutability: Mutability::Mut, lifetime: l, ty: Box::new(t) }, + "&" => Ty::Ref{ mutability: Mutability::Not, lifetime: l, ty: Box::new(t) }, }; ScalarType: ScalarType = { @@ -238,7 +240,7 @@ TupleOrParensInner: Ty = { () => Ty::Tuple { types: vec![] }, }; -Mutability: Mutability = { +RawMutability: Mutability = { "mut" => Mutability::Mut, "const" => Mutability::Not, }; diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 24e076d7025..44fb2d00eee 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -411,6 +411,7 @@ fn match_type_name( builder.push_fact(WellFormed::Ty(application.clone().intern(interner))) } TypeName::Raw(_) => builder.push_fact(WellFormed::Ty(application.clone().intern(interner))), + TypeName::Ref(_) => builder.push_fact(WellFormed::Ty(application.clone().intern(interner))), } } diff --git a/chalk-solve/src/clauses/builtin_traits/copy.rs b/chalk-solve/src/clauses/builtin_traits/copy.rs index f6b4627315c..fda824d407f 100644 --- a/chalk-solve/src/clauses/builtin_traits/copy.rs +++ b/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -41,7 +41,7 @@ pub fn add_copy_program_clauses( TypeName::Tuple(arity) => { push_tuple_copy_conditions(db, builder, trait_ref, *arity, substitution) } - TypeName::Raw(_) => builder.push_fact(trait_ref.clone()), + TypeName::Raw(_) | TypeName::Ref(_) => builder.push_fact(trait_ref.clone()), _ => return, }, TyData::Function(_) => builder.push_fact(trait_ref.clone()), diff --git a/chalk-solve/src/clauses/builtin_traits/sized.rs b/chalk-solve/src/clauses/builtin_traits/sized.rs index f9f57e15f3a..c0cf2492892 100644 --- a/chalk-solve/src/clauses/builtin_traits/sized.rs +++ b/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -71,11 +71,12 @@ pub fn add_sized_program_clauses( TypeName::Struct(struct_id) => { push_struct_sized_conditions(db, builder, trait_ref, *struct_id, substitution) } - TypeName::Scalar(_) => builder.push_fact(trait_ref.clone()), TypeName::Tuple(arity) => { push_tuple_sized_conditions(db, builder, trait_ref, *arity, substitution) } - TypeName::Raw(_) => builder.push_fact(trait_ref.clone()), + TypeName::Scalar(_) | TypeName::Raw(_) | TypeName::Ref(_) => { + builder.push_fact(trait_ref.clone()) + } _ => return, }, TyData::Function(_) => builder.push_fact(trait_ref.clone()), diff --git a/tests/lowering/mod.rs b/tests/lowering/mod.rs index 8c9cb0aabc8..89021cfeca5 100644 --- a/tests/lowering/mod.rs +++ b/tests/lowering/mod.rs @@ -471,7 +471,7 @@ fn scalars() { } error_msg { - "parse error: UnrecognizedToken { token: (8, Token(51, \"i32\"), 11), expected: [\"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }" + "parse error: UnrecognizedToken { token: (8, Token(52, \"i32\"), 11), expected: [\"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }" } } } @@ -495,7 +495,7 @@ fn raw_pointers() { struct *const i32 { } } error_msg { - "parse error: UnrecognizedToken { token: (8, Token(7, \"*\"), 9), expected: [\"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }" + "parse error: UnrecognizedToken { token: (8, Token(8, \"*\"), 9), expected: [\"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }" } } @@ -505,7 +505,31 @@ fn raw_pointers() { impl Foo for *i32 { } } error_msg { - "parse error: UnrecognizedToken { token: (30, Token(51, \"i32\"), 33), expected: [\"\\\"const\\\"\", \"\\\"mut\\\"\"] }" + "parse error: UnrecognizedToken { token: (30, Token(52, \"i32\"), 33), expected: [\"\\\"const\\\"\", \"\\\"mut\\\"\"] }" + } + } +} + +#[test] +fn refs() { + lowering_success! { + program { + trait Foo { } + + impl<'a, T> Foo for &'a T { } + impl<'b, T> Foo for &'b mut T { } + } + } + + lowering_error! { + program { + trait Foo { } + + impl Foo for &T { } + } + + error_msg { + "parse error: UnrecognizedToken { token: (36, Token(1, \"T\"), 37), expected: [\"r#\\\"\\\\\\\'([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }" } } } diff --git a/tests/test/mod.rs b/tests/test/mod.rs index 3b85a82d787..e502f20235e 100644 --- a/tests/test/mod.rs +++ b/tests/test/mod.rs @@ -314,6 +314,7 @@ mod impls; mod misc; mod negation; mod projection; +mod refs; mod scalars; mod tuples; mod unify; diff --git a/tests/test/refs.rs b/tests/test/refs.rs new file mode 100644 index 00000000000..e8f2f78d923 --- /dev/null +++ b/tests/test/refs.rs @@ -0,0 +1,62 @@ +use super::*; + +#[test] +fn refs_are_well_formed() { + test! { + program { } + + goal { + forall<'a, T> { WellFormed(&'a T) } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +} + +#[test] +fn refs_are_sized() { + test! { + program { + #[lang(sized)] + trait Sized { } + } + + goal { + forall<'a, T> { &'a T: Sized } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +} + +#[test] +fn refs_are_copy() { + test! { + program { + #[lang(copy)] + trait Copy { } + } + + goal { + forall<'a, T> { &'a T: Copy } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +} + +#[test] +fn refs_are_clone() { + test! { + program { + #[lang(clone)] + trait Clone { } + } + + goal { + forall<'a, T> { &'a T: Clone } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +}