From 16a7d8cc850002b427fdc8d21ccde81caaed7902 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 13 Aug 2019 23:09:08 +0200 Subject: Add `impl Trait` and `dyn Trait` types - refactor bounds handling in the AST a bit - add HIR for bounds - add `Ty::Dyn` and `Ty::Opaque` variants and lower `dyn Trait` / `impl Trait` syntax to them --- crates/ra_hir/src/ty/lower.rs | 65 +++++++++++++++---- crates/ra_hir/src/ty/tests.rs | 120 +++++++++++++++++++++++++++++++++++ crates/ra_hir/src/ty/traits/chalk.rs | 4 +- 3 files changed, 177 insertions(+), 12 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index debedcbb8..47d161277 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -17,7 +17,7 @@ use crate::{ path::{GenericArg, PathSegment}, resolve::{Resolution, Resolver}, ty::AdtDef, - type_ref::TypeRef, + type_ref::{TypeBound, TypeRef}, BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct, StructField, Trait, TypeAlias, Union, }; @@ -58,6 +58,22 @@ impl Ty { let sig = Substs(inner_tys.into()); Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) } + TypeRef::DynTrait(bounds) => { + let self_ty = Ty::Bound(0); + let predicates = bounds + .iter() + .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) + .collect::>(); + Ty::Dyn(predicates.into()) + } + TypeRef::ImplTrait(bounds) => { + let self_ty = Ty::Bound(0); + let predicates = bounds + .iter() + .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) + .collect::>(); + Ty::Opaque(predicates.into()) + } TypeRef::Error => Ty::Unknown, } } @@ -310,13 +326,46 @@ impl TraitRef { TraitRef { trait_, substs } } - pub(crate) fn for_where_predicate( + pub(crate) fn from_where_predicate( db: &impl HirDatabase, resolver: &Resolver, pred: &WherePredicate, ) -> Option { let self_ty = Ty::from_hir(db, resolver, &pred.type_ref); - TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty)) + TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty) + } + + pub(crate) fn from_type_bound( + db: &impl HirDatabase, + resolver: &Resolver, + bound: &TypeBound, + self_ty: Ty, + ) -> Option { + match bound { + TypeBound::Path(path) => TraitRef::from_path(db, resolver, path, Some(self_ty)), + TypeBound::Error => None, + } + } +} + +impl GenericPredicate { + pub(crate) fn from_where_predicate( + db: &impl HirDatabase, + resolver: &Resolver, + where_predicate: &WherePredicate, + ) -> GenericPredicate { + TraitRef::from_where_predicate(db, &resolver, where_predicate) + .map_or(GenericPredicate::Error, GenericPredicate::Implemented) + } + + pub(crate) fn from_type_bound( + db: &impl HirDatabase, + resolver: &Resolver, + bound: &TypeBound, + self_ty: Ty, + ) -> GenericPredicate { + TraitRef::from_type_bound(db, &resolver, bound, self_ty) + .map_or(GenericPredicate::Error, GenericPredicate::Implemented) } } @@ -376,10 +425,7 @@ pub(crate) fn trait_env( ) -> Arc { let predicates = resolver .where_predicates_in_scope() - .map(|pred| { - TraitRef::for_where_predicate(db, &resolver, pred) - .map_or(GenericPredicate::Error, GenericPredicate::Implemented) - }) + .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) .collect::>(); Arc::new(super::TraitEnvironment { predicates }) @@ -393,10 +439,7 @@ pub(crate) fn generic_predicates_query( let resolver = def.resolver(db); let predicates = resolver .where_predicates_in_scope() - .map(|pred| { - TraitRef::for_where_predicate(db, &resolver, pred) - .map_or(GenericPredicate::Error, GenericPredicate::Implemented) - }) + .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) .collect::>(); predicates.into() } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 57fd5492d..93c62b0d4 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3273,6 +3273,126 @@ fn test(t: T) { assert_eq!(t, "{unknown}"); } +#[test] +fn impl_trait() { + assert_snapshot_matches!( + infer(r#" +trait Trait { + fn foo(&self) -> T; +} +fn bar() -> impl Trait {} + +fn test(x: impl Trait, y: &impl Trait) { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); +} +"#), + @r###" + ⋮ + ⋮[30; 34) 'self': &Self + ⋮[72; 74) '{}': () + ⋮[84; 85) 'x': impl Trait + ⋮[104; 105) 'y': &impl Trait + ⋮[125; 200) '{ ...o(); }': () + ⋮[131; 132) 'x': impl Trait + ⋮[138; 139) 'y': &impl Trait + ⋮[149; 150) 'z': impl Trait + ⋮[153; 156) 'bar': fn bar() -> impl Trait + ⋮[153; 158) 'bar()': impl Trait + ⋮[164; 165) 'x': impl Trait + ⋮[164; 171) 'x.foo()': {unknown} + ⋮[177; 178) 'y': &impl Trait + ⋮[177; 184) 'y.foo()': {unknown} + ⋮[190; 191) 'z': impl Trait + ⋮[190; 197) 'z.foo()': {unknown} + "### + ); +} + +#[test] +fn dyn_trait() { + assert_snapshot_matches!( + infer(r#" +trait Trait { + fn foo(&self) -> T; +} +fn bar() -> dyn Trait {} + +fn test(x: dyn Trait, y: &dyn Trait) { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); +} +"#), + @r###" + ⋮ + ⋮[30; 34) 'self': &Self + ⋮[71; 73) '{}': () + ⋮[83; 84) 'x': dyn Trait + ⋮[102; 103) 'y': &dyn Trait + ⋮[122; 197) '{ ...o(); }': () + ⋮[128; 129) 'x': dyn Trait + ⋮[135; 136) 'y': &dyn Trait + ⋮[146; 147) 'z': dyn Trait + ⋮[150; 153) 'bar': fn bar() -> dyn Trait + ⋮[150; 155) 'bar()': dyn Trait + ⋮[161; 162) 'x': dyn Trait + ⋮[161; 168) 'x.foo()': {unknown} + ⋮[174; 175) 'y': &dyn Trait + ⋮[174; 181) 'y.foo()': {unknown} + ⋮[187; 188) 'z': dyn Trait + ⋮[187; 194) 'z.foo()': {unknown} + "### + ); +} + +#[test] +fn dyn_trait_bare() { + assert_snapshot_matches!( + infer(r#" +trait Trait { + fn foo(&self) -> u64; +} +fn bar() -> Trait {} + +fn test(x: Trait, y: &Trait) -> u64 { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); +} +"#), + @r###" + ⋮ + ⋮[27; 31) 'self': &Self + ⋮[61; 63) '{}': () + ⋮[73; 74) 'x': {unknown} + ⋮[83; 84) 'y': &{unknown} + ⋮[101; 176) '{ ...o(); }': () + ⋮[107; 108) 'x': {unknown} + ⋮[114; 115) 'y': &{unknown} + ⋮[125; 126) 'z': {unknown} + ⋮[129; 132) 'bar': fn bar() -> {unknown} + ⋮[129; 134) 'bar()': {unknown} + ⋮[140; 141) 'x': {unknown} + ⋮[140; 147) 'x.foo()': {unknown} + ⋮[153; 154) 'y': &{unknown} + ⋮[153; 160) 'y.foo()': {unknown} + ⋮[166; 167) 'z': {unknown} + ⋮[166; 173) 'z.foo()': {unknown} + "### + ); +} + fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 6df7094c5..2ebc06135 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -80,7 +80,9 @@ impl ToChalk for Ty { // FIXME this is clearly incorrect, but probably not too incorrect // and I'm not sure what to actually do with Ty::Unknown // maybe an alternative would be `for T`? (meaningless in rust, but expressible in chalk's Ty) - Ty::Unknown => { + // + // FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet + Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() } } -- cgit v1.2.3