From 22a65b11b3a69b3dae561b34c6b28cb2107169d1 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 24 Jan 2020 14:32:47 +0100 Subject: [PATCH 01/25] Introduce TyLoweringContext --- crates/ra_hir/src/code_model.rs | 11 +- crates/ra_hir/src/source_analyzer.rs | 9 +- crates/ra_hir_ty/src/infer.rs | 17 +- crates/ra_hir_ty/src/infer/path.rs | 25 ++- crates/ra_hir_ty/src/lib.rs | 2 +- crates/ra_hir_ty/src/lower.rs | 232 +++++++++++++-------------- 6 files changed, 144 insertions(+), 152 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index eaacf8c9eda..837a3ed6dd7 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -733,7 +733,8 @@ impl Local { let ty = infer[self.pat_id].clone(); let resolver = def.resolver(db); let krate = def.module(db).krate; - let environment = TraitEnvironment::lower(db, &resolver); + let ctx = hir_ty::TyLoweringContext { db, resolver: &resolver }; + let environment = TraitEnvironment::lower(&ctx); Type { krate, ty: InEnvironment { value: ty, environment } } } @@ -789,8 +790,9 @@ impl ImplBlock { pub fn target_ty(&self, db: &impl HirDatabase) -> Type { let impl_data = db.impl_data(self.id); let resolver = self.id.resolver(db); - let environment = TraitEnvironment::lower(db, &resolver); - let ty = Ty::from_hir(db, &resolver, &impl_data.target_type); + let ctx = hir_ty::TyLoweringContext { db, resolver: &resolver }; + let environment = TraitEnvironment::lower(&ctx); + let ty = Ty::from_hir(&ctx, &impl_data.target_type); Type { krate: self.id.lookup(db).container.module(db).krate, ty: InEnvironment { value: ty, environment }, @@ -844,7 +846,8 @@ pub struct Type { impl Type { fn new(db: &impl HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { let resolver = lexical_env.resolver(db); - let environment = TraitEnvironment::lower(db, &resolver); + let ctx = hir_ty::TyLoweringContext { db, resolver: &resolver }; + let environment = TraitEnvironment::lower(&ctx); Type { krate, ty: InEnvironment { value: ty, environment } } } diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 4f8fc960202..9cfd52856a2 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -178,6 +178,11 @@ impl SourceAnalyzer { } } + fn trait_env(&self, db: &impl HirDatabase) -> Arc { + let ctx = hir_ty::TyLoweringContext { db, resolver: &self.resolver }; + TraitEnvironment::lower(&ctx) + } + pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option { let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) { self.body_source_map.as_ref()?.node_expr(expr.as_ref())? @@ -186,14 +191,14 @@ impl SourceAnalyzer { }; let ty = self.infer.as_ref()?[expr_id].clone(); - let environment = TraitEnvironment::lower(db, &self.resolver); + let environment = self.trait_env(db); Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option { let pat_id = self.pat_id(pat)?; let ty = self.infer.as_ref()?[pat_id].clone(); - let environment = TraitEnvironment::lower(db, &self.resolver); + let environment = self.trait_env(db); Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index e2eda3134b7..e27ce6e9175 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -215,12 +215,13 @@ struct InferenceContext<'a, D: HirDatabase> { impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn new(db: &'a D, owner: DefWithBodyId, resolver: Resolver) -> Self { + let ctx = crate::lower::TyLoweringContext { db, resolver: &resolver }; InferenceContext { result: InferenceResult::default(), table: unify::InferenceTable::new(), obligations: Vec::default(), return_ty: Ty::Unknown, // set in collect_fn_signature - trait_env: TraitEnvironment::lower(db, &resolver), + trait_env: TraitEnvironment::lower(&ctx), coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), db, owner, @@ -272,12 +273,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { - let ty = Ty::from_hir( - self.db, - // FIXME use right resolver for block - &self.resolver, - type_ref, - ); + // FIXME use right resolver for block + let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let ty = Ty::from_hir(&ctx, type_ref); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) } @@ -446,17 +444,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { None => return (Ty::Unknown, None), }; let resolver = &self.resolver; + let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; // FIXME: this should resolve assoc items as well, see this example: // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) { Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { - let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into()); + let substs = Ty::substs_from_path(&ctx, path, strukt.into()); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.apply_substs(substs)); (ty, Some(strukt.into())) } Some(TypeNs::EnumVariantId(var)) => { - let substs = Ty::substs_from_path(self.db, resolver, path, var.into()); + let substs = Ty::substs_from_path(&ctx, path, var.into()); let ty = self.db.ty(var.parent.into()); let ty = self.insert_type_vars(ty.apply_substs(substs)); (ty, Some(var.into())) diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 2c1d4831d7e..132f3d6f239 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -11,7 +11,7 @@ use hir_expand::name::Name; use crate::{db::HirDatabase, method_resolution, Substs, Ty, TypeWalk, ValueTyDefId}; -use super::{ExprOrPatId, InferenceContext, TraitEnvironment, TraitRef}; +use super::{ExprOrPatId, InferenceContext, TraitRef}; impl<'a, D: HirDatabase> InferenceContext<'a, D> { pub(super) fn infer_path( @@ -39,7 +39,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } let ty = self.make_ty(type_ref); let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); - let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); + let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &resolver }; + let ty = Ty::from_type_relative_path(&ctx, ty, remaining_segments_for_ty); self.resolve_ty_assoc_item( ty, &path.segments().last().expect("path had at least one segment").name, @@ -73,7 +74,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if let Some(self_subst) = self_subst { ty = ty.subst(&self_subst); } - let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); + let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let substs = Ty::substs_from_path(&ctx, path, typable); let ty = ty.subst(&substs); Some(ty) } @@ -98,13 +100,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { (TypeNs::TraitId(trait_), true) => { let segment = remaining_segments.last().expect("there should be at least one segment here"); - let trait_ref = TraitRef::from_resolved_path( - self.db, - &self.resolver, - trait_.into(), - resolved_segment, - None, - ); + let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let trait_ref = + TraitRef::from_resolved_path(&ctx, trait_.into(), resolved_segment, None); self.resolve_trait_assoc_item(trait_ref, segment, id) } (def, _) => { @@ -114,9 +112,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // as Iterator>::Item::default`) let remaining_segments_for_ty = remaining_segments.take(remaining_segments.len() - 1); + let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; let ty = Ty::from_partly_resolved_hir_path( - self.db, - &self.resolver, + &ctx, def, resolved_segment, remaining_segments_for_ty, @@ -193,14 +191,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); - let env = TraitEnvironment::lower(self.db, &self.resolver); let krate = self.resolver.krate()?; let traits_in_scope = self.resolver.traits_in_scope(self.db); method_resolution::iterate_method_candidates( &canonical_ty.value, self.db, - env, + self.trait_env.clone(), krate, &traits_in_scope, Some(name), diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 08d501ccd33..6f0e8b4817a 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -60,7 +60,7 @@ use display::{HirDisplay, HirFormatter}; pub use autoderef::autoderef; pub use infer::{do_infer_query, InferTy, InferenceResult}; pub use lower::CallableDef; -pub use lower::{callable_item_sig, TyDefId, ValueTyDefId}; +pub use lower::{callable_item_sig, TyDefId, TyLoweringContext, ValueTyDefId}; pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; /// A type constructor or type name: this might be something like the primitive diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 2c2ecee9cc6..87c984e3fe2 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -31,47 +31,50 @@ use crate::{ Ty, TypeCtor, TypeWalk, }; +#[derive(Clone, Debug)] +pub struct TyLoweringContext<'a, DB: HirDatabase> { + pub db: &'a DB, + pub resolver: &'a Resolver, +} + impl Ty { - pub fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { + pub fn from_hir(ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef) -> Self { match type_ref { TypeRef::Never => Ty::simple(TypeCtor::Never), TypeRef::Tuple(inner) => { - let inner_tys: Arc<[Ty]> = - inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect(); + let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| Ty::from_hir(ctx, tr)).collect(); Ty::apply( TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, Substs(inner_tys), ) } - TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path), + TypeRef::Path(path) => Ty::from_hir_path(ctx, path), TypeRef::RawPtr(inner, mutability) => { - let inner_ty = Ty::from_hir(db, resolver, inner); + let inner_ty = Ty::from_hir(ctx, inner); Ty::apply_one(TypeCtor::RawPtr(*mutability), inner_ty) } TypeRef::Array(inner) => { - let inner_ty = Ty::from_hir(db, resolver, inner); + let inner_ty = Ty::from_hir(ctx, inner); Ty::apply_one(TypeCtor::Array, inner_ty) } TypeRef::Slice(inner) => { - let inner_ty = Ty::from_hir(db, resolver, inner); + let inner_ty = Ty::from_hir(ctx, inner); Ty::apply_one(TypeCtor::Slice, inner_ty) } TypeRef::Reference(inner, mutability) => { - let inner_ty = Ty::from_hir(db, resolver, inner); + let inner_ty = Ty::from_hir(ctx, inner); Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) } TypeRef::Placeholder => Ty::Unknown, TypeRef::Fn(params) => { - let sig = Substs(params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect()); + let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect()); 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() - .flat_map(|b| { - GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) - }) + .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) .collect(); Ty::Dyn(predicates) } @@ -79,9 +82,7 @@ impl Ty { let self_ty = Ty::Bound(0); let predicates = bounds .iter() - .flat_map(|b| { - GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) - }) + .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) .collect(); Ty::Opaque(predicates) } @@ -93,8 +94,7 @@ impl Ty { /// lower the self types of the predicates since that could lead to cycles. /// So we just check here if the `type_ref` resolves to a generic param, and which. fn from_hir_only_param( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef, ) -> Option { let path = match type_ref { @@ -107,12 +107,12 @@ impl Ty { if path.segments().len() > 1 { return None; } - let resolution = match resolver.resolve_path_in_type_ns(db, path.mod_path()) { + let resolution = match ctx.resolver.resolve_path_in_type_ns(ctx.db, path.mod_path()) { Some((it, None)) => it, _ => return None, }; if let TypeNs::GenericParam(param_id) = resolution { - let generics = generics(db, resolver.generic_def().expect("generics in scope")); + let generics = generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); let idx = generics.param_idx(param_id); Some(idx) } else { @@ -121,15 +121,14 @@ impl Ty { } pub(crate) fn from_type_relative_path( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, ty: Ty, remaining_segments: PathSegments<'_>, ) -> Ty { if remaining_segments.len() == 1 { // resolve unselected assoc types let segment = remaining_segments.first().unwrap(); - Ty::select_associated_type(db, resolver, ty, segment) + Ty::select_associated_type(ctx, ty, segment) } else if remaining_segments.len() > 1 { // FIXME report error (ambiguous associated type) Ty::Unknown @@ -139,20 +138,18 @@ impl Ty { } pub(crate) fn from_partly_resolved_hir_path( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, resolution: TypeNs, resolved_segment: PathSegment<'_>, remaining_segments: PathSegments<'_>, ) -> Ty { let ty = match resolution { TypeNs::TraitId(trait_) => { - let trait_ref = - TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); + let trait_ref = TraitRef::from_resolved_path(ctx, trait_, resolved_segment, None); return if remaining_segments.len() == 1 { let segment = remaining_segments.first().unwrap(); let associated_ty = associated_type_by_name_including_super_traits( - db, + ctx.db, trait_ref.trait_, &segment.name, ); @@ -177,37 +174,34 @@ impl Ty { }; } TypeNs::GenericParam(param_id) => { - let generics = generics(db, resolver.generic_def().expect("generics in scope")); + let generics = + generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); let idx = generics.param_idx(param_id); // FIXME: maybe return name in resolution? let name = generics.param_name(param_id); Ty::Param { idx, name } } - TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(), - TypeNs::AdtSelfType(adt) => db.ty(adt.into()), + TypeNs::SelfType(impl_id) => ctx.db.impl_self_ty(impl_id).clone(), + TypeNs::AdtSelfType(adt) => ctx.db.ty(adt.into()), - TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), - TypeNs::BuiltinType(it) => { - Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) - } - TypeNs::TypeAliasId(it) => { - Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) - } + TypeNs::AdtId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), + TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), + TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), // FIXME: report error TypeNs::EnumVariantId(_) => return Ty::Unknown, }; - Ty::from_type_relative_path(db, resolver, ty, remaining_segments) + Ty::from_type_relative_path(ctx, ty, remaining_segments) } - pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { + pub(crate) fn from_hir_path(ctx: &TyLoweringContext<'_, impl HirDatabase>, path: &Path) -> Ty { // Resolve the path (in type namespace) if let Some(type_ref) = path.type_anchor() { - let ty = Ty::from_hir(db, resolver, &type_ref); - return Ty::from_type_relative_path(db, resolver, ty, path.segments()); + let ty = Ty::from_hir(ctx, &type_ref); + return Ty::from_type_relative_path(ctx, ty, path.segments()); } let (resolution, remaining_index) = - match resolver.resolve_path_in_type_ns(db, path.mod_path()) { + match ctx.resolver.resolve_path_in_type_ns(ctx.db, path.mod_path()) { Some(it) => it, None => return Ty::Unknown, }; @@ -218,18 +212,11 @@ impl Ty { ), Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), }; - Ty::from_partly_resolved_hir_path( - db, - resolver, - resolution, - resolved_segment, - remaining_segments, - ) + Ty::from_partly_resolved_hir_path(ctx, resolution, resolved_segment, remaining_segments) } fn select_associated_type( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, self_ty: Ty, segment: PathSegment<'_>, ) -> Ty { @@ -237,20 +224,23 @@ impl Ty { Ty::Param { idx, .. } => idx, _ => return Ty::Unknown, // Error: Ambiguous associated type }; - let def = match resolver.generic_def() { + let def = match ctx.resolver.generic_def() { Some(def) => def, None => return Ty::Unknown, // this can't actually happen }; - let predicates = db.generic_predicates_for_param(def.into(), param_idx); + let predicates = ctx.db.generic_predicates_for_param(def.into(), param_idx); let traits_from_env = predicates.iter().filter_map(|pred| match pred { GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_), _ => None, }); - let traits = traits_from_env.flat_map(|t| all_super_traits(db, t)); + let traits = traits_from_env.flat_map(|t| all_super_traits(ctx.db, t)); for t in traits { - if let Some(associated_ty) = db.trait_data(t).associated_type_by_name(&segment.name) { - let substs = - Substs::build_for_def(db, t).push(self_ty.clone()).fill_with_unknown().build(); + if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) + { + let substs = Substs::build_for_def(ctx.db, t) + .push(self_ty.clone()) + .fill_with_unknown() + .build(); // FIXME handle type parameters on the segment return Ty::Projection(ProjectionTy { associated_ty, parameters: substs }); } @@ -259,8 +249,7 @@ impl Ty { } fn from_hir_path_inner( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, segment: PathSegment<'_>, typable: TyDefId, ) -> Ty { @@ -269,15 +258,14 @@ impl Ty { TyDefId::AdtId(it) => Some(it.into()), TyDefId::TypeAliasId(it) => Some(it.into()), }; - let substs = substs_from_path_segment(db, resolver, segment, generic_def, false); - db.ty(typable).subst(&substs) + let substs = substs_from_path_segment(ctx, segment, generic_def, false); + ctx.db.ty(typable).subst(&substs) } /// Collect generic arguments from a path into a `Substs`. See also /// `create_substs_for_ast_path` and `def_to_ty` in rustc. pub(super) fn substs_from_path( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, path: &Path, // Note that we don't call `db.value_type(resolved)` here, // `ValueTyDefId` is just a convenient way to pass generics and @@ -305,19 +293,18 @@ impl Ty { (segment, Some(var.parent.into())) } }; - substs_from_path_segment(db, resolver, segment, generic_def, false) + substs_from_path_segment(ctx, segment, generic_def, false) } } pub(super) fn substs_from_path_segment( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, segment: PathSegment<'_>, def_generic: Option, add_self_param: bool, ) -> Substs { let mut substs = Vec::new(); - let def_generics = def_generic.map(|def| generics(db, def.into())); + let def_generics = def_generic.map(|def| generics(ctx.db, def.into())); let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split()); substs.extend(iter::repeat(Ty::Unknown).take(parent_len)); @@ -335,7 +322,7 @@ pub(super) fn substs_from_path_segment( for arg in generic_args.args.iter().take(child_len) { match arg { GenericArg::Type(type_ref) => { - let ty = Ty::from_hir(db, resolver, type_ref); + let ty = Ty::from_hir(ctx, type_ref); substs.push(ty); } } @@ -350,7 +337,7 @@ pub(super) fn substs_from_path_segment( // handle defaults if let Some(def_generic) = def_generic { - let default_substs = db.generic_defaults(def_generic.into()); + let default_substs = ctx.db.generic_defaults(def_generic.into()); assert_eq!(substs.len(), default_substs.len()); for (i, default_ty) in default_substs.iter().enumerate() { @@ -365,27 +352,25 @@ pub(super) fn substs_from_path_segment( impl TraitRef { fn from_path( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, path: &Path, explicit_self_ty: Option, ) -> Option { - let resolved = match resolver.resolve_path_in_type_ns_fully(db, path.mod_path())? { + let resolved = match ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path.mod_path())? { TypeNs::TraitId(tr) => tr, _ => return None, }; let segment = path.segments().last().expect("path should have at least one segment"); - Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty)) + Some(TraitRef::from_resolved_path(ctx, resolved.into(), segment, explicit_self_ty)) } pub(crate) fn from_resolved_path( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, resolved: TraitId, segment: PathSegment<'_>, explicit_self_ty: Option, ) -> Self { - let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); + let mut substs = TraitRef::substs_from_path(ctx, segment, resolved); if let Some(self_ty) = explicit_self_ty { make_mut_slice(&mut substs.0)[0] = self_ty; } @@ -393,8 +378,7 @@ impl TraitRef { } fn from_hir( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef, explicit_self_ty: Option, ) -> Option { @@ -402,28 +386,26 @@ impl TraitRef { TypeRef::Path(path) => path, _ => return None, }; - TraitRef::from_path(db, resolver, path, explicit_self_ty) + TraitRef::from_path(ctx, path, explicit_self_ty) } fn substs_from_path( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, segment: PathSegment<'_>, resolved: TraitId, ) -> Substs { let has_self_param = segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); - substs_from_path_segment(db, resolver, segment, Some(resolved.into()), !has_self_param) + substs_from_path_segment(ctx, segment, Some(resolved.into()), !has_self_param) } pub(crate) fn from_type_bound( - db: &impl HirDatabase, - resolver: &Resolver, + ctx: &TyLoweringContext<'_, impl HirDatabase>, bound: &TypeBound, self_ty: Ty, ) -> Option { match bound { - TypeBound::Path(path) => TraitRef::from_path(db, resolver, path, Some(self_ty)), + TypeBound::Path(path) => TraitRef::from_path(ctx, path, Some(self_ty)), TypeBound::Error => None, } } @@ -431,33 +413,30 @@ impl TraitRef { impl GenericPredicate { pub(crate) fn from_where_predicate<'a>( - db: &'a impl HirDatabase, - resolver: &'a Resolver, + ctx: &'a TyLoweringContext<'a, impl HirDatabase>, where_predicate: &'a WherePredicate, ) -> impl Iterator + 'a { - let self_ty = Ty::from_hir(db, resolver, &where_predicate.type_ref); - GenericPredicate::from_type_bound(db, resolver, &where_predicate.bound, self_ty) + let self_ty = Ty::from_hir(ctx, &where_predicate.type_ref); + GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty) } pub(crate) fn from_type_bound<'a>( - db: &'a impl HirDatabase, - resolver: &'a Resolver, + ctx: &'a TyLoweringContext<'a, impl HirDatabase>, bound: &'a TypeBound, self_ty: Ty, ) -> impl Iterator + 'a { - let trait_ref = TraitRef::from_type_bound(db, &resolver, bound, self_ty); + let trait_ref = TraitRef::from_type_bound(ctx, bound, self_ty); iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented)) .chain( - trait_ref.into_iter().flat_map(move |tr| { - assoc_type_bindings_from_type_bound(db, resolver, bound, tr) - }), + trait_ref + .into_iter() + .flat_map(move |tr| assoc_type_bindings_from_type_bound(ctx, bound, tr)), ) } } fn assoc_type_bindings_from_type_bound<'a>( - db: &'a impl HirDatabase, - resolver: &'a Resolver, + ctx: &'a TyLoweringContext<'a, impl HirDatabase>, bound: &'a TypeBound, trait_ref: TraitRef, ) -> impl Iterator + 'a { @@ -471,14 +450,14 @@ fn assoc_type_bindings_from_type_bound<'a>( .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) .map(move |(name, type_ref)| { let associated_ty = - associated_type_by_name_including_super_traits(db, trait_ref.trait_, &name); + associated_type_by_name_including_super_traits(ctx.db, trait_ref.trait_, &name); let associated_ty = match associated_ty { None => return GenericPredicate::Error, Some(t) => t, }; let projection_ty = ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; - let ty = Ty::from_hir(db, resolver, type_ref); + let ty = Ty::from_hir(ctx, type_ref); let projection_predicate = ProjectionPredicate { projection_ty, ty }; GenericPredicate::Projection(projection_predicate) }) @@ -505,8 +484,9 @@ pub(crate) fn field_types_query( VariantId::EnumVariantId(it) => it.parent.resolver(db), }; let mut res = ArenaMap::default(); + let ctx = TyLoweringContext { db, resolver: &resolver }; for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, Ty::from_hir(db, &resolver, &field_data.type_ref)) + res.insert(field_id, Ty::from_hir(&ctx, &field_data.type_ref)) } Arc::new(res) } @@ -525,11 +505,12 @@ pub(crate) fn generic_predicates_for_param_query( param_idx: u32, ) -> Arc<[GenericPredicate]> { let resolver = def.resolver(db); + let ctx = TyLoweringContext { db, resolver: &resolver }; resolver .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them - .filter(|pred| Ty::from_hir_only_param(db, &resolver, &pred.type_ref) == Some(param_idx)) - .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) + .filter(|pred| Ty::from_hir_only_param(&ctx, &pred.type_ref) == Some(param_idx)) + .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect() } @@ -543,10 +524,11 @@ pub(crate) fn generic_predicates_for_param_recover( } impl TraitEnvironment { - pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { - let predicates = resolver + pub fn lower(ctx: &TyLoweringContext<'_, impl HirDatabase>) -> Arc { + let predicates = ctx + .resolver .where_predicates_in_scope() - .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) + .flat_map(|pred| GenericPredicate::from_where_predicate(ctx, pred)) .collect::>(); Arc::new(TraitEnvironment { predicates }) @@ -559,20 +541,22 @@ pub(crate) fn generic_predicates_query( def: GenericDefId, ) -> Arc<[GenericPredicate]> { let resolver = def.resolver(db); + let ctx = TyLoweringContext { db, resolver: &resolver }; resolver .where_predicates_in_scope() - .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) + .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect() } /// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { let resolver = def.resolver(db); + let ctx = TyLoweringContext { db, resolver: &resolver }; let generic_params = generics(db, def.into()); let defaults = generic_params .iter() - .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t))) + .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t))) .collect(); Substs(defaults) @@ -581,8 +565,9 @@ pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) - fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig { let data = db.function_data(def); let resolver = def.resolver(db); - let params = data.params.iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::>(); - let ret = Ty::from_hir(db, &resolver, &data.ret_type); + let ctx = TyLoweringContext { db, resolver: &resolver }; + let params = data.params.iter().map(|tr| Ty::from_hir(&ctx, tr)).collect::>(); + let ret = Ty::from_hir(&ctx, &data.ret_type); FnSig::from_params_and_return(params, ret) } @@ -598,16 +583,18 @@ fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { fn type_for_const(db: &impl HirDatabase, def: ConstId) -> Ty { let data = db.const_data(def); let resolver = def.resolver(db); + let ctx = TyLoweringContext { db, resolver: &resolver }; - Ty::from_hir(db, &resolver, &data.type_ref) + Ty::from_hir(&ctx, &data.type_ref) } /// Build the declared type of a static. fn type_for_static(db: &impl HirDatabase, def: StaticId) -> Ty { let data = db.static_data(def); let resolver = def.resolver(db); + let ctx = TyLoweringContext { db, resolver: &resolver }; - Ty::from_hir(db, &resolver, &data.type_ref) + Ty::from_hir(&ctx, &data.type_ref) } /// Build the declared type of a static. @@ -625,10 +612,9 @@ fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> FnSig let struct_data = db.struct_data(def.into()); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db); - let params = fields - .iter() - .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) - .collect::>(); + let ctx = TyLoweringContext { db, resolver: &resolver }; + let params = + fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let ret = type_for_adt(db, def.into()); FnSig::from_params_and_return(params, ret) } @@ -649,10 +635,9 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId let var_data = &enum_data.variants[def.local_id]; let fields = var_data.variant_data.fields(); let resolver = def.parent.resolver(db); - let params = fields - .iter() - .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) - .collect::>(); + let ctx = TyLoweringContext { db, resolver: &resolver }; + let params = + fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let generics = generics(db, def.parent.into()); let substs = Substs::identity(&generics); let ret = type_for_adt(db, def.parent.into()).subst(&substs); @@ -679,9 +664,10 @@ fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { let generics = generics(db, t.into()); let resolver = t.resolver(db); + let ctx = TyLoweringContext { db, resolver: &resolver }; let type_ref = &db.type_alias_data(t).type_ref; let substs = Substs::identity(&generics); - let inner = Ty::from_hir(db, &resolver, type_ref.as_ref().unwrap_or(&TypeRef::Error)); + let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); inner.subst(&substs) } @@ -761,7 +747,8 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - Ty::from_hir(db, &resolver, &impl_data.target_type) + let ctx = TyLoweringContext { db, resolver: &resolver }; + Ty::from_hir(&ctx, &impl_data.target_type) } pub(crate) fn impl_self_ty_recover( @@ -775,7 +762,8 @@ pub(crate) fn impl_self_ty_recover( pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); + let ctx = TyLoweringContext { db, resolver: &resolver }; let self_ty = db.impl_self_ty(impl_id); let target_trait = impl_data.target_trait.as_ref()?; - TraitRef::from_hir(db, &resolver, target_trait, Some(self_ty.clone())) + TraitRef::from_hir(&ctx, target_trait, Some(self_ty.clone())) } From 7ea4bce1b292d455c313f914b3aa3051293c502b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 24 Jan 2020 15:22:00 +0100 Subject: [PATCH 02/25] Add impl trait lowering mode --- crates/ra_hir/src/code_model.rs | 14 ++-- crates/ra_hir/src/source_analyzer.rs | 3 +- crates/ra_hir_ty/src/infer.rs | 33 +++++++--- crates/ra_hir_ty/src/infer/path.rs | 29 ++++++-- crates/ra_hir_ty/src/lib.rs | 4 +- crates/ra_hir_ty/src/lower.rs | 98 +++++++++++++++++++++++----- 6 files changed, 141 insertions(+), 40 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 837a3ed6dd7..fda31d5177c 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -733,8 +733,7 @@ impl Local { let ty = infer[self.pat_id].clone(); let resolver = def.resolver(db); let krate = def.module(db).krate; - let ctx = hir_ty::TyLoweringContext { db, resolver: &resolver }; - let environment = TraitEnvironment::lower(&ctx); + let environment = TraitEnvironment::lower(db, &resolver); Type { krate, ty: InEnvironment { value: ty, environment } } } @@ -790,8 +789,12 @@ impl ImplBlock { pub fn target_ty(&self, db: &impl HirDatabase) -> Type { let impl_data = db.impl_data(self.id); let resolver = self.id.resolver(db); - let ctx = hir_ty::TyLoweringContext { db, resolver: &resolver }; - let environment = TraitEnvironment::lower(&ctx); + let ctx = hir_ty::TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: hir_ty::ImplTraitLoweringMode::Disallowed, + }; + let environment = TraitEnvironment::lower(db, &resolver); let ty = Ty::from_hir(&ctx, &impl_data.target_type); Type { krate: self.id.lookup(db).container.module(db).krate, @@ -846,8 +849,7 @@ pub struct Type { impl Type { fn new(db: &impl HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { let resolver = lexical_env.resolver(db); - let ctx = hir_ty::TyLoweringContext { db, resolver: &resolver }; - let environment = TraitEnvironment::lower(&ctx); + let environment = TraitEnvironment::lower(db, &resolver); Type { krate, ty: InEnvironment { value: ty, environment } } } diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 9cfd52856a2..bb9a35c5d12 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -179,8 +179,7 @@ impl SourceAnalyzer { } fn trait_env(&self, db: &impl HirDatabase) -> Arc { - let ctx = hir_ty::TyLoweringContext { db, resolver: &self.resolver }; - TraitEnvironment::lower(&ctx) + TraitEnvironment::lower(db, &self.resolver) } pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option { diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index e27ce6e9175..b4a3e16755c 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -42,7 +42,9 @@ use super::{ ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, }; -use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; +use crate::{ + db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, +}; pub(crate) use unify::unify; @@ -215,13 +217,12 @@ struct InferenceContext<'a, D: HirDatabase> { impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn new(db: &'a D, owner: DefWithBodyId, resolver: Resolver) -> Self { - let ctx = crate::lower::TyLoweringContext { db, resolver: &resolver }; InferenceContext { result: InferenceResult::default(), table: unify::InferenceTable::new(), obligations: Vec::default(), return_ty: Ty::Unknown, // set in collect_fn_signature - trait_env: TraitEnvironment::lower(&ctx), + trait_env: TraitEnvironment::lower(db, &resolver), coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), db, owner, @@ -272,14 +273,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.result.diagnostics.push(diagnostic); } - fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { + fn make_ty_with_mode( + &mut self, + type_ref: &TypeRef, + impl_trait_mode: ImplTraitLoweringMode, + ) -> Ty { // FIXME use right resolver for block - let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let ctx = crate::lower::TyLoweringContext { + db: self.db, + resolver: &self.resolver, + impl_trait_mode, + }; let ty = Ty::from_hir(&ctx, type_ref); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) } + fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { + self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed) + } + /// Replaces `impl Trait` in `ty` by type variables and obligations for /// those variables. This is done for function arguments when calling a /// function, and for return types when inside the function body, i.e. in @@ -444,7 +457,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { None => return (Ty::Unknown, None), }; let resolver = &self.resolver; - let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let ctx = crate::lower::TyLoweringContext { + db: self.db, + resolver: &self.resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; // FIXME: this should resolve assoc items as well, see this example: // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) { @@ -471,11 +488,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn collect_fn(&mut self, data: &FunctionData) { let body = Arc::clone(&self.body); // avoid borrow checker problem for (type_ref, pat) in data.params.iter().zip(body.params.iter()) { - let ty = self.make_ty(type_ref); + let ty = self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Opaque); self.infer_pat(*pat, &ty, BindingMode::default()); } - let return_ty = self.make_ty(&data.ret_type); + let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Placeholder); self.return_ty = self.insert_vars_for_impl_trait(return_ty); } diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 132f3d6f239..02fc9928887 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -9,7 +9,10 @@ use hir_def::{ }; use hir_expand::name::Name; -use crate::{db::HirDatabase, method_resolution, Substs, Ty, TypeWalk, ValueTyDefId}; +use crate::{ + db::HirDatabase, lower::ImplTraitLoweringMode, method_resolution, Substs, Ty, TypeWalk, + ValueTyDefId, +}; use super::{ExprOrPatId, InferenceContext, TraitRef}; @@ -39,7 +42,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } let ty = self.make_ty(type_ref); let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); - let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &resolver }; + let ctx = crate::lower::TyLoweringContext { + db: self.db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let ty = Ty::from_type_relative_path(&ctx, ty, remaining_segments_for_ty); self.resolve_ty_assoc_item( ty, @@ -74,7 +81,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if let Some(self_subst) = self_subst { ty = ty.subst(&self_subst); } - let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let ctx = crate::lower::TyLoweringContext { + db: self.db, + resolver: &self.resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let substs = Ty::substs_from_path(&ctx, path, typable); let ty = ty.subst(&substs); Some(ty) @@ -100,7 +111,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { (TypeNs::TraitId(trait_), true) => { let segment = remaining_segments.last().expect("there should be at least one segment here"); - let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let ctx = crate::lower::TyLoweringContext { + db: self.db, + resolver: &self.resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let trait_ref = TraitRef::from_resolved_path(&ctx, trait_.into(), resolved_segment, None); self.resolve_trait_assoc_item(trait_ref, segment, id) @@ -112,7 +127,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // as Iterator>::Item::default`) let remaining_segments_for_ty = remaining_segments.take(remaining_segments.len() - 1); - let ctx = crate::lower::TyLoweringContext { db: self.db, resolver: &self.resolver }; + let ctx = crate::lower::TyLoweringContext { + db: self.db, + resolver: &self.resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let ty = Ty::from_partly_resolved_hir_path( &ctx, def, diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 6f0e8b4817a..c64b81f9848 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -60,7 +60,9 @@ use display::{HirDisplay, HirFormatter}; pub use autoderef::autoderef; pub use infer::{do_infer_query, InferTy, InferenceResult}; pub use lower::CallableDef; -pub use lower::{callable_item_sig, TyDefId, TyLoweringContext, ValueTyDefId}; +pub use lower::{ + callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, +}; pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; /// A type constructor or type name: this might be something like the primitive diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 87c984e3fe2..3d242122397 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -35,6 +35,14 @@ use crate::{ pub struct TyLoweringContext<'a, DB: HirDatabase> { pub db: &'a DB, pub resolver: &'a Resolver, + pub impl_trait_mode: ImplTraitLoweringMode, +} + +#[derive(Clone, Debug)] +pub enum ImplTraitLoweringMode { + Opaque, + Placeholder, + Disallowed, } impl Ty { @@ -484,7 +492,11 @@ pub(crate) fn field_types_query( VariantId::EnumVariantId(it) => it.parent.resolver(db), }; let mut res = ArenaMap::default(); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, Ty::from_hir(&ctx, &field_data.type_ref)) } @@ -505,7 +517,11 @@ pub(crate) fn generic_predicates_for_param_query( param_idx: u32, ) -> Arc<[GenericPredicate]> { let resolver = def.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; resolver .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them @@ -524,11 +540,12 @@ pub(crate) fn generic_predicates_for_param_recover( } impl TraitEnvironment { - pub fn lower(ctx: &TyLoweringContext<'_, impl HirDatabase>) -> Arc { - let predicates = ctx - .resolver + pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { + let ctx = + TyLoweringContext { db, resolver, impl_trait_mode: ImplTraitLoweringMode::Disallowed }; + let predicates = resolver .where_predicates_in_scope() - .flat_map(|pred| GenericPredicate::from_where_predicate(ctx, pred)) + .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect::>(); Arc::new(TraitEnvironment { predicates }) @@ -541,7 +558,11 @@ pub(crate) fn generic_predicates_query( def: GenericDefId, ) -> Arc<[GenericPredicate]> { let resolver = def.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; resolver .where_predicates_in_scope() .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) @@ -551,7 +572,11 @@ pub(crate) fn generic_predicates_query( /// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { let resolver = def.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let generic_params = generics(db, def.into()); let defaults = generic_params @@ -565,9 +590,18 @@ pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) - fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig { let data = db.function_data(def); let resolver = def.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; - let params = data.params.iter().map(|tr| Ty::from_hir(&ctx, tr)).collect::>(); - let ret = Ty::from_hir(&ctx, &data.ret_type); + let ctx_params = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Placeholder, + }; + let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::>(); + let ctx_ret = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Opaque, + }; + let ret = Ty::from_hir(&ctx_ret, &data.ret_type); FnSig::from_params_and_return(params, ret) } @@ -583,7 +617,11 @@ fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { fn type_for_const(db: &impl HirDatabase, def: ConstId) -> Ty { let data = db.const_data(def); let resolver = def.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; Ty::from_hir(&ctx, &data.type_ref) } @@ -592,7 +630,11 @@ fn type_for_const(db: &impl HirDatabase, def: ConstId) -> Ty { fn type_for_static(db: &impl HirDatabase, def: StaticId) -> Ty { let data = db.static_data(def); let resolver = def.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; Ty::from_hir(&ctx, &data.type_ref) } @@ -612,7 +654,11 @@ fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> FnSig let struct_data = db.struct_data(def.into()); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let params = fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let ret = type_for_adt(db, def.into()); @@ -635,7 +681,11 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId let var_data = &enum_data.variants[def.local_id]; let fields = var_data.variant_data.fields(); let resolver = def.parent.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let params = fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let generics = generics(db, def.parent.into()); @@ -664,7 +714,11 @@ fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { let generics = generics(db, t.into()); let resolver = t.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let type_ref = &db.type_alias_data(t).type_ref; let substs = Substs::identity(&generics); let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); @@ -747,7 +801,11 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; Ty::from_hir(&ctx, &impl_data.target_type) } @@ -762,7 +820,11 @@ pub(crate) fn impl_self_ty_recover( pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - let ctx = TyLoweringContext { db, resolver: &resolver }; + let ctx = TyLoweringContext { + db, + resolver: &resolver, + impl_trait_mode: ImplTraitLoweringMode::Disallowed, + }; let self_ty = db.impl_self_ty(impl_id); let target_trait = impl_data.target_trait.as_ref()?; TraitRef::from_hir(&ctx, target_trait, Some(self_ty.clone())) From 9dec65d3b1aa703ceef993e46136f8949d7e0e48 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 24 Jan 2020 16:46:43 +0100 Subject: [PATCH 03/25] wip implement lowering mode --- crates/ra_hir_ty/src/lower.rs | 32 ++++++++++++++++++++++------ crates/ra_hir_ty/src/tests/traits.rs | 28 +++++++----------------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 3d242122397..39406d8cec5 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -40,8 +40,17 @@ pub struct TyLoweringContext<'a, DB: HirDatabase> { #[derive(Clone, Debug)] pub enum ImplTraitLoweringMode { + /// `impl Trait` gets lowered into an opaque type that doesn't unify with + /// anything except itself. This is used in places where values flow 'out', + /// i.e. for arguments of the function we're currently checking, and return + /// types of functions we're calling. Opaque, + /// `impl Trait` gets lowered into a placeholder that can unify with some + /// type. This is used in places where values flow 'in', i.e. for arguments + /// of functions we're calling, and the return type of the function we're + /// currently checking. Placeholder, + /// `impl Trait` is disallowed and will be an error. Disallowed, } @@ -87,12 +96,23 @@ impl Ty { Ty::Dyn(predicates) } TypeRef::ImplTrait(bounds) => { - let self_ty = Ty::Bound(0); - let predicates = bounds - .iter() - .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) - .collect(); - Ty::Opaque(predicates) + match ctx.impl_trait_mode { + ImplTraitLoweringMode::Opaque => { + let self_ty = Ty::Bound(0); + let predicates = bounds + .iter() + .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) + .collect(); + Ty::Opaque(predicates) + }, + ImplTraitLoweringMode::Placeholder => { + todo!() + }, + ImplTraitLoweringMode::Disallowed => { + // FIXME: report error + Ty::Unknown + }, + } } TypeRef::Error => Ty::Unknown, } diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index a6ac18f86ce..764ab280017 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -994,29 +994,17 @@ fn weird_bounds() { assert_snapshot!( infer(r#" trait Trait {} -fn test() { - let a: impl Trait + 'lifetime = foo; - let b: impl 'lifetime = foo; - let b: impl (Trait) = foo; - let b: impl ('lifetime) = foo; - let d: impl ?Sized = foo; - let e: impl Trait + ?Sized = foo; +fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl ('lifetime), e: impl ?Sized, f: impl Trait + ?Sized) { } "#), @r###" - [26; 237) '{ ...foo; }': () - [36; 37) 'a': impl Trait + {error} - [64; 67) 'foo': impl Trait + {error} - [77; 78) 'b': impl {error} - [97; 100) 'foo': impl {error} - [110; 111) 'b': impl Trait - [128; 131) 'foo': impl Trait - [141; 142) 'b': impl {error} - [163; 166) 'foo': impl {error} - [176; 177) 'd': impl {error} - [193; 196) 'foo': impl {error} - [206; 207) 'e': impl Trait + {error} - [231; 234) 'foo': impl Trait + {error} + [24; 25) 'a': impl Trait + {error} + [51; 52) 'b': impl {error} + [70; 71) 'c': impl Trait + [87; 88) 'd': impl {error} + [108; 109) 'e': impl {error} + [124; 125) 'f': impl Trait + {error} + [148; 151) '{ }': () "### ); } From 93aa166748eef9560df2435391dc3f3b53f8262d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 24 Jan 2020 19:35:09 +0100 Subject: [PATCH 04/25] wip lower impl trait to type args --- crates/ra_hir/src/code_model.rs | 2 +- crates/ra_hir_def/src/generics.rs | 45 ++++++++++++++++++++++++++---- crates/ra_hir_def/src/resolver.rs | 10 ++++--- crates/ra_hir_def/src/type_ref.rs | 44 +++++++++++++++++++++++++++++ crates/ra_hir_ty/src/infer/expr.rs | 4 +-- crates/ra_hir_ty/src/lib.rs | 2 +- crates/ra_hir_ty/src/lower.rs | 1 + crates/ra_hir_ty/src/utils.rs | 3 +- 8 files changed, 97 insertions(+), 14 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index fda31d5177c..817c27410a1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -755,7 +755,7 @@ pub struct TypeParam { impl TypeParam { pub fn name(self, db: &impl HirDatabase) -> Name { let params = db.generic_params(self.id.parent); - params.types[self.id.local_id].name.clone() + params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing) } pub fn module(self, db: &impl HirDatabase) -> Module { diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index e9c28c7309e..7553d8a8719 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -27,8 +27,16 @@ use crate::{ /// Data about a generic parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug)] pub struct TypeParamData { - pub name: Name, + pub name: Option, pub default: Option, + pub provenance: TypeParamProvenance, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum TypeParamProvenance { + TypeParamList, + TraitSelf, + ArgumentImplTrait, } /// Data about the generic parameters of a function, struct, impl, etc. @@ -68,6 +76,11 @@ impl GenericParams { GenericDefId::FunctionId(it) => { let src = it.lookup(db).source(db); generics.fill(&mut sm, &src.value); + // lower `impl Trait` in arguments + let data = db.function_data(it); + for param in &data.params { + generics.fill_implicit_impl_trait_args(param); + } src.file_id } GenericDefId::AdtId(AdtId::StructId(it)) => { @@ -89,8 +102,11 @@ impl GenericParams { let src = it.lookup(db).source(db); // traits get the Self type as an implicit first type parameter - let self_param_id = - generics.types.alloc(TypeParamData { name: name![Self], default: None }); + let self_param_id = generics.types.alloc(TypeParamData { + name: Some(name![Self]), + default: None, + provenance: TypeParamProvenance::TraitSelf, + }); sm.insert(self_param_id, Either::Left(src.value.clone())); // add super traits as bounds on Self // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar @@ -142,7 +158,11 @@ impl GenericParams { let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); // FIXME: Use `Path::from_src` let default = type_param.default_type().map(TypeRef::from_ast); - let param = TypeParamData { name: name.clone(), default }; + let param = TypeParamData { + name: Some(name.clone()), + default, + provenance: TypeParamProvenance::TypeParamList, + }; let param_id = self.types.alloc(param); sm.insert(param_id, Either::Right(type_param.clone())); @@ -173,8 +193,23 @@ impl GenericParams { self.where_predicates.push(WherePredicate { type_ref, bound }); } + fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { + type_ref.walk(&mut |type_ref| { + if let TypeRef::ImplTrait(_) = type_ref { + let param = TypeParamData { + name: None, + default: None, + provenance: TypeParamProvenance::ArgumentImplTrait, + }; + let _param_id = self.types.alloc(param); + } + }); + } + pub fn find_by_name(&self, name: &Name) -> Option { - self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None }) + self.types + .iter() + .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) } } diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index f7bac580112..05cf4646a89 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs @@ -490,10 +490,12 @@ impl Scope { } Scope::GenericParams { params, def } => { for (local_id, param) in params.types.iter() { - f( - param.name.clone(), - ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }), - ) + if let Some(name) = ¶m.name { + f( + name.clone(), + ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }), + ) + } } } Scope::ImplBlockScope(i) => { diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index 5f10e9a88ba..10941477053 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs @@ -124,6 +124,50 @@ impl TypeRef { pub(crate) fn unit() -> TypeRef { TypeRef::Tuple(Vec::new()) } + + pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) { + go(self, f); + + fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { + f(type_ref); + match type_ref { + TypeRef::Fn(types) | TypeRef::Tuple(types) => { + types.iter().for_each(|t| go(t, f)) + } + TypeRef::RawPtr(type_ref, _) + | TypeRef::Reference(type_ref, _) + | TypeRef::Array(type_ref) + | TypeRef::Slice(type_ref) => go(&type_ref, f), + TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { + for bound in bounds { + match bound { + TypeBound::Path(path) => go_path(path, f), + TypeBound::Error => (), + } + } + } + TypeRef::Path(path) => go_path(path, f), + TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {} + }; + } + + fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) { + if let Some(type_ref) = path.type_anchor() { + go(type_ref, f); + } + for segment in path.segments().iter() { + if let Some(args_and_bindings) = segment.args_and_bindings { + for arg in &args_and_bindings.args { + let crate::path::GenericArg::Type(type_ref) = arg; + go(type_ref, f); + } + for (_, type_ref) in &args_and_bindings.bindings { + go(type_ref, f); + } + } + } + } + } } pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option) -> Vec { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 31259a01de7..97cb20cea40 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -10,7 +10,7 @@ use hir_def::{ resolver::resolver_for_expr, AdtId, AssocContainerId, Lookup, StructFieldId, }; -use hir_expand::name::{name, Name}; +use hir_expand::name::Name; use ra_syntax::ast::RangeOp; use crate::{ @@ -654,7 +654,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Parent arguments are unknown, except for the receiver type if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { for (_id, param) in parent_generics { - if param.name == name![Self] { + if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf { substs.push(receiver_ty.clone()); } else { substs.push(Ty::Unknown); diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index c64b81f9848..cb7a60352fd 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -368,7 +368,7 @@ impl Substs { /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). pub(crate) fn identity(generic_params: &Generics) -> Substs { Substs( - generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(), + generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone().unwrap_or_else(Name::missing) }).collect(), ) } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 39406d8cec5..6f768147520 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -341,6 +341,7 @@ pub(super) fn substs_from_path_segment( // Self type as an implicit first type parameter, but it can't be // actually provided in the type arguments // (well, actually sometimes it can, in the form of type-relative paths: `::default()`) + // TODO handle this using type param provenance substs.push(Ty::Unknown); } if let Some(generic_args) = &segment.args_and_bindings { diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 0b1806a84fd..314a3241f9d 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -127,7 +127,8 @@ impl Generics { self.find_param(param).0 } pub(crate) fn param_name(&self, param: TypeParamId) -> Name { - self.find_param(param).1.name.clone() + // FIXME make this return Option + self.find_param(param).1.name.clone().unwrap_or_else(Name::missing) } fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) { if param.parent == self.def { From 16c69374471a0072541c21a5551b4fd97f7e12ba Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 25 Jan 2020 23:38:33 +0100 Subject: [PATCH 05/25] Lower impl trait to variables, move away from using placeholders where they don't belong --- crates/ra_hir_ty/src/db.rs | 12 +- crates/ra_hir_ty/src/infer.rs | 18 +- crates/ra_hir_ty/src/infer/expr.rs | 6 +- crates/ra_hir_ty/src/infer/path.rs | 55 ++--- crates/ra_hir_ty/src/lib.rs | 34 ++- crates/ra_hir_ty/src/lower.rs | 263 ++++++++++++---------- crates/ra_hir_ty/src/method_resolution.rs | 4 +- crates/ra_hir_ty/src/tests/simple.rs | 2 +- crates/ra_hir_ty/src/utils.rs | 14 +- 9 files changed, 220 insertions(+), 188 deletions(-) diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index eb521c7a064..fea122a8b96 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -12,8 +12,8 @@ use ra_prof::profile; use crate::{ method_resolution::CrateImplBlocks, traits::{chalk, AssocTyValue, Impl}, - CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor, - ValueTyDefId, + CallableDef, PolyFnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor, + ValueTyDefId, Binders, }; #[salsa::query_group(HirDatabaseStorage)] @@ -27,14 +27,14 @@ pub trait HirDatabase: DefDatabase { #[salsa::invoke(crate::lower::ty_query)] #[salsa::cycle(crate::lower::ty_recover)] - fn ty(&self, def: TyDefId) -> Ty; + fn ty(&self, def: TyDefId) -> Binders; #[salsa::invoke(crate::lower::value_ty_query)] - fn value_ty(&self, def: ValueTyDefId) -> Ty; + fn value_ty(&self, def: ValueTyDefId) -> Binders; #[salsa::invoke(crate::lower::impl_self_ty_query)] #[salsa::cycle(crate::lower::impl_self_ty_recover)] - fn impl_self_ty(&self, def: ImplId) -> Ty; + fn impl_self_ty(&self, def: ImplId) -> Binders; #[salsa::invoke(crate::lower::impl_trait_query)] fn impl_trait(&self, def: ImplId) -> Option; @@ -43,7 +43,7 @@ pub trait HirDatabase: DefDatabase { fn field_types(&self, var: VariantId) -> Arc>; #[salsa::invoke(crate::callable_item_sig)] - fn callable_item_signature(&self, def: CallableDef) -> FnSig; + fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index b4a3e16755c..f7ef09f0eea 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -279,11 +279,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { impl_trait_mode: ImplTraitLoweringMode, ) -> Ty { // FIXME use right resolver for block - let ctx = crate::lower::TyLoweringContext { - db: self.db, - resolver: &self.resolver, - impl_trait_mode, - }; + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver).with_impl_trait_mode(impl_trait_mode); let ty = Ty::from_hir(&ctx, type_ref); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) @@ -457,24 +453,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { None => return (Ty::Unknown, None), }; let resolver = &self.resolver; - let ctx = crate::lower::TyLoweringContext { - db: self.db, - resolver: &self.resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); // FIXME: this should resolve assoc items as well, see this example: // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) { Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { let substs = Ty::substs_from_path(&ctx, path, strukt.into()); let ty = self.db.ty(strukt.into()); - let ty = self.insert_type_vars(ty.apply_substs(substs)); + let ty = self.insert_type_vars(ty.subst(&substs)); (ty, Some(strukt.into())) } Some(TypeNs::EnumVariantId(var)) => { let substs = Ty::substs_from_path(&ctx, path, var.into()); let ty = self.db.ty(var.parent.into()); - let ty = self.insert_type_vars(ty.apply_substs(substs)); + let ty = self.insert_type_vars(ty.subst(&substs)); (ty, Some(var.into())) } Some(_) | None => (Ty::Unknown, None), @@ -492,7 +484,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.infer_pat(*pat, &ty, BindingMode::default()); } - let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Placeholder); + let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Variable); self.return_ty = self.insert_vars_for_impl_trait(return_ty); } diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 97cb20cea40..e1fdb356df8 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -20,7 +20,7 @@ use crate::{ traits::InEnvironment, utils::{generics, variant_data, Generics}, ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty, - TypeCtor, TypeWalk, Uncertain, + TypeCtor, TypeWalk, Uncertain, Binders, }; use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; @@ -588,10 +588,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.write_method_resolution(tgt_expr, func); (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into()))) } - None => (receiver_ty, Ty::Unknown, None), + None => (receiver_ty, Binders::new(0, Ty::Unknown), None), }; let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); - let method_ty = method_ty.apply_substs(substs); + let method_ty = method_ty.subst(&substs); let method_ty = self.insert_type_vars(method_ty); self.register_obligations_for_call(&method_ty); let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 02fc9928887..39aa346eb32 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -10,8 +10,8 @@ use hir_def::{ use hir_expand::name::Name; use crate::{ - db::HirDatabase, lower::ImplTraitLoweringMode, method_resolution, Substs, Ty, TypeWalk, - ValueTyDefId, + db::HirDatabase, method_resolution, Substs, Ty, + ValueTyDefId }; use super::{ExprOrPatId, InferenceContext, TraitRef}; @@ -42,11 +42,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } let ty = self.make_ty(type_ref); let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); - let ctx = crate::lower::TyLoweringContext { - db: self.db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver); let ty = Ty::from_type_relative_path(&ctx, ty, remaining_segments_for_ty); self.resolve_ty_assoc_item( ty, @@ -77,17 +73,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ValueNs::EnumVariantId(it) => it.into(), }; - let mut ty = self.db.value_ty(typable); - if let Some(self_subst) = self_subst { - ty = ty.subst(&self_subst); - } - let ctx = crate::lower::TyLoweringContext { - db: self.db, - resolver: &self.resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ty = self.db.value_ty(typable); + // self_subst is just for the parent + let parent_substs = self_subst.unwrap_or_else(Substs::empty); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); let substs = Ty::substs_from_path(&ctx, path, typable); - let ty = ty.subst(&substs); + let full_substs = Substs::builder(substs.len()) + .use_parent_substs(&parent_substs) + .fill(substs.0[parent_substs.len()..].iter().cloned()) + .build(); + let ty = ty.subst(&full_substs); Some(ty) } @@ -111,11 +106,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { (TypeNs::TraitId(trait_), true) => { let segment = remaining_segments.last().expect("there should be at least one segment here"); - let ctx = crate::lower::TyLoweringContext { - db: self.db, - resolver: &self.resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); let trait_ref = TraitRef::from_resolved_path(&ctx, trait_.into(), resolved_segment, None); self.resolve_trait_assoc_item(trait_ref, segment, id) @@ -127,11 +118,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // as Iterator>::Item::default`) let remaining_segments_for_ty = remaining_segments.take(remaining_segments.len() - 1); - let ctx = crate::lower::TyLoweringContext { - db: self.db, - resolver: &self.resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); let ty = Ty::from_partly_resolved_hir_path( &ctx, def, @@ -235,12 +222,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .fill(iter::repeat_with(|| self.table.new_type_var())) .build(); let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); - let substs = Substs::build_for_def(self.db, item) - .use_parent_substs(&impl_substs) - .fill_with_params() - .build(); self.unify(&impl_self_ty, &ty); - Some(substs) + Some(impl_substs) } AssocContainerId::TraitId(trait_) => { // we're picking this method @@ -248,15 +231,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .push(ty.clone()) .fill(std::iter::repeat_with(|| self.table.new_type_var())) .build(); - let substs = Substs::build_for_def(self.db, item) - .use_parent_substs(&trait_substs) - .fill_with_params() - .build(); self.obligations.push(super::Obligation::Trait(TraitRef { trait_, - substs: trait_substs, + substs: trait_substs.clone(), })); - Some(substs) + Some(trait_substs) } AssocContainerId::ContainerId(_) => None, }; diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index cb7a60352fd..79084bb3e0e 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -453,6 +453,30 @@ impl Deref for Substs { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Binders { + pub num_binders: usize, + pub value: T, +} + +impl Binders { + pub fn new(num_binders: usize, value: T) -> Self { Self { num_binders, value } } +} + +impl Binders { + /// Substitutes all variables. + pub fn subst(self, subst: &Substs) -> T { + assert_eq!(subst.len(), self.num_binders); + self.value.subst_bound_vars(subst) + } + + /// Substitutes just a prefix of the variables (shifting the rest). + pub fn subst_prefix(self, subst: &Substs) -> Binders { + assert!(subst.len() < self.num_binders); + Binders::new(self.num_binders - subst.len(), self.value.subst_bound_vars(subst)) + } +} + /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. /// Name to be bikeshedded: TraitBound? TraitImplements? #[derive(Clone, PartialEq, Eq, Debug, Hash)] @@ -553,6 +577,9 @@ pub struct FnSig { params_and_return: Arc<[Ty]>, } +/// A polymorphic function signature. +pub type PolyFnSig = Binders; + impl FnSig { pub fn from_params_and_return(mut params: Vec, ret: Ty) -> FnSig { params.push(ret); @@ -757,6 +784,9 @@ pub trait TypeWalk { &mut Ty::Bound(idx) => { if idx as usize >= binders && (idx as usize - binders) < substs.len() { *ty = substs.0[idx as usize - binders].clone(); + } else if idx as usize >= binders + substs.len() { + // shift free binders + *ty = Ty::Bound(idx - substs.len() as u32); } } _ => {} @@ -903,8 +933,8 @@ impl HirDisplay for ApplicationTy { write!(f, ">")?; } write!(f, "(")?; - f.write_joined(sig.params(), ", ")?; - write!(f, ") -> {}", sig.ret().display(f.db))?; + f.write_joined(sig.value.params(), ", ")?; + write!(f, ") -> {}", sig.value.ret().display(f.db))?; } TypeCtor::Adt(def_id) => { let name = match def_id { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 6f768147520..006101f2f7c 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -28,32 +28,62 @@ use crate::{ variant_data, }, FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, - Ty, TypeCtor, TypeWalk, + Ty, TypeCtor, PolyFnSig, Binders, }; -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct TyLoweringContext<'a, DB: HirDatabase> { pub db: &'a DB, pub resolver: &'a Resolver, + /// Note: Conceptually, it's thinkable that we could be in a location where + /// some type params are quantified universally (and should be represented + /// as placeholders), and others are quantified existentially (and should be + /// converted to variables). I think in practice, this isn't possible + /// currently, so this should be fine for now. + pub type_param_mode: TypeParamLoweringMode, pub impl_trait_mode: ImplTraitLoweringMode, + pub impl_trait_counter: std::cell::Cell, } -#[derive(Clone, Debug)] +impl<'a, DB: HirDatabase> TyLoweringContext<'a, DB> { + pub fn new(db: &'a DB, resolver: &'a Resolver) -> Self { + let impl_trait_counter = std::cell::Cell::new(0); + let impl_trait_mode = ImplTraitLoweringMode::Disallowed; + let type_param_mode = TypeParamLoweringMode::Placeholder; + Self { db, resolver, impl_trait_mode, impl_trait_counter, type_param_mode } + } + + pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { + Self { impl_trait_mode, ..self } + } + + pub fn with_type_param_mode(self, type_param_mode: TypeParamLoweringMode) -> Self { + Self { type_param_mode, ..self } + } +} + +#[derive(Copy, Clone, Debug)] pub enum ImplTraitLoweringMode { /// `impl Trait` gets lowered into an opaque type that doesn't unify with /// anything except itself. This is used in places where values flow 'out', /// i.e. for arguments of the function we're currently checking, and return /// types of functions we're calling. Opaque, - /// `impl Trait` gets lowered into a placeholder that can unify with some + /// `impl Trait` gets lowered into a variable that can unify with some /// type. This is used in places where values flow 'in', i.e. for arguments /// of functions we're calling, and the return type of the function we're /// currently checking. - Placeholder, + Variable, /// `impl Trait` is disallowed and will be an error. Disallowed, } +#[derive(Copy, Clone, Debug)] +pub enum TypeParamLoweringMode { + Placeholder, + Variable, +} + impl Ty { pub fn from_hir(ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef) -> Self { match type_ref { @@ -101,17 +131,25 @@ impl Ty { let self_ty = Ty::Bound(0); let predicates = bounds .iter() - .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) + .flat_map(|b| { + GenericPredicate::from_type_bound(ctx, b, self_ty.clone()) + }) .collect(); Ty::Opaque(predicates) - }, - ImplTraitLoweringMode::Placeholder => { - todo!() - }, + } + ImplTraitLoweringMode::Variable => { + let idx = ctx.impl_trait_counter.get(); + ctx.impl_trait_counter.set(idx + 1); + let generics = + generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); + let (self_params, list_params, impl_trait_params) = generics.provenance_split(); + assert!((idx as usize) < impl_trait_params); + Ty::Bound(idx as u32 + self_params as u32 + list_params as u32) + } ImplTraitLoweringMode::Disallowed => { // FIXME: report error Ty::Unknown - }, + } } } TypeRef::Error => Ty::Unknown, @@ -205,12 +243,31 @@ impl Ty { let generics = generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); let idx = generics.param_idx(param_id); - // FIXME: maybe return name in resolution? - let name = generics.param_name(param_id); - Ty::Param { idx, name } + match ctx.type_param_mode { + TypeParamLoweringMode::Placeholder => { + // FIXME: maybe return name in resolution? + let name = generics.param_name(param_id); + Ty::Param { idx, name } + }, + TypeParamLoweringMode::Variable => Ty::Bound(idx), + } } - TypeNs::SelfType(impl_id) => ctx.db.impl_self_ty(impl_id).clone(), - TypeNs::AdtSelfType(adt) => ctx.db.ty(adt.into()), + TypeNs::SelfType(impl_id) => { + let generics = generics(ctx.db, impl_id.into()); + let substs = match ctx.type_param_mode { + TypeParamLoweringMode::Placeholder => Substs::identity(&generics), + TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), + }; + ctx.db.impl_self_ty(impl_id).subst(&substs) + }, + TypeNs::AdtSelfType(adt) => { + let generics = generics(ctx.db, adt.into()); + let substs = match ctx.type_param_mode { + TypeParamLoweringMode::Placeholder => Substs::identity(&generics), + TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), + }; + ctx.db.ty(adt.into()).subst(&substs) + }, TypeNs::AdtId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), @@ -341,7 +398,7 @@ pub(super) fn substs_from_path_segment( // Self type as an implicit first type parameter, but it can't be // actually provided in the type arguments // (well, actually sometimes it can, in the form of type-relative paths: `::default()`) - // TODO handle this using type param provenance + // TODO handle this using type param provenance (if there's a self param, and not one provided, add unknown) substs.push(Ty::Unknown); } if let Some(generic_args) = &segment.args_and_bindings { @@ -493,7 +550,7 @@ fn assoc_type_bindings_from_type_bound<'a>( } /// Build the signature of a callable item (function, struct or enum variant). -pub fn callable_item_sig(db: &impl HirDatabase, def: CallableDef) -> FnSig { +pub fn callable_item_sig(db: &impl HirDatabase, def: CallableDef) -> PolyFnSig { match def { CallableDef::FunctionId(f) => fn_sig_for_fn(db, f), CallableDef::StructId(s) => fn_sig_for_struct_constructor(db, s), @@ -513,11 +570,7 @@ pub(crate) fn field_types_query( VariantId::EnumVariantId(it) => it.parent.resolver(db), }; let mut res = ArenaMap::default(); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, Ty::from_hir(&ctx, &field_data.type_ref)) } @@ -538,11 +591,7 @@ pub(crate) fn generic_predicates_for_param_query( param_idx: u32, ) -> Arc<[GenericPredicate]> { let resolver = def.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver); resolver .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them @@ -562,8 +611,7 @@ pub(crate) fn generic_predicates_for_param_recover( impl TraitEnvironment { pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { - let ctx = - TyLoweringContext { db, resolver, impl_trait_mode: ImplTraitLoweringMode::Disallowed }; + let ctx = TyLoweringContext::new(db, &resolver); let predicates = resolver .where_predicates_in_scope() .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) @@ -579,11 +627,7 @@ pub(crate) fn generic_predicates_query( def: GenericDefId, ) -> Arc<[GenericPredicate]> { let resolver = def.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver); resolver .where_predicates_in_scope() .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) @@ -593,11 +637,7 @@ pub(crate) fn generic_predicates_query( /// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { let resolver = def.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver); let generic_params = generics(db, def.into()); let defaults = generic_params @@ -608,56 +648,46 @@ pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) - Substs(defaults) } -fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig { +fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> PolyFnSig { let data = db.function_data(def); let resolver = def.resolver(db); - let ctx_params = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Placeholder, - }; + let ctx_params = TyLoweringContext::new(db, &resolver) + .with_impl_trait_mode(ImplTraitLoweringMode::Variable) + .with_type_param_mode(TypeParamLoweringMode::Variable); let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::>(); - let ctx_ret = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Opaque, - }; + let ctx_ret = ctx_params.with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let ret = Ty::from_hir(&ctx_ret, &data.ret_type); - FnSig::from_params_and_return(params, ret) + let generics = generics(db, def.into()); + let num_binders = generics.len(); + Binders::new(num_binders, FnSig::from_params_and_return(params, ret)) } /// Build the declared type of a function. This should not need to look at the /// function body. -fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { +fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Binders { let generics = generics(db, def.into()); - let substs = Substs::identity(&generics); - Ty::apply(TypeCtor::FnDef(def.into()), substs) + let substs = Substs::bound_vars(&generics); + Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) } /// Build the declared type of a const. -fn type_for_const(db: &impl HirDatabase, def: ConstId) -> Ty { +fn type_for_const(db: &impl HirDatabase, def: ConstId) -> Binders { let data = db.const_data(def); + let generics = generics(db, def.into()); let resolver = def.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Variable); - Ty::from_hir(&ctx, &data.type_ref) + Binders::new(generics.len(), Ty::from_hir(&ctx, &data.type_ref)) } /// Build the declared type of a static. -fn type_for_static(db: &impl HirDatabase, def: StaticId) -> Ty { +fn type_for_static(db: &impl HirDatabase, def: StaticId) -> Binders { let data = db.static_data(def); let resolver = def.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver); - Ty::from_hir(&ctx, &data.type_ref) + Binders::new(0, Ty::from_hir(&ctx, &data.type_ref)) } /// Build the declared type of a static. @@ -671,79 +701,71 @@ fn type_for_builtin(def: BuiltinType) -> Ty { }) } -fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> FnSig { +fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> PolyFnSig { let struct_data = db.struct_data(def.into()); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let ret = type_for_adt(db, def.into()); - FnSig::from_params_and_return(params, ret) + Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) } /// Build the type of a tuple struct constructor. -fn type_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> Ty { +fn type_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> Binders { let struct_data = db.struct_data(def.into()); if struct_data.variant_data.is_unit() { return type_for_adt(db, def.into()); // Unit struct } let generics = generics(db, def.into()); - let substs = Substs::identity(&generics); - Ty::apply(TypeCtor::FnDef(def.into()), substs) + let substs = Substs::bound_vars(&generics); + Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(def.into()), substs)) } -fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId) -> FnSig { +fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId) -> PolyFnSig { let enum_data = db.enum_data(def.parent); let var_data = &enum_data.variants[def.local_id]; let fields = var_data.variant_data.fields(); let resolver = def.parent.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver); let params = fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let generics = generics(db, def.parent.into()); - let substs = Substs::identity(&generics); + let substs = Substs::bound_vars(&generics); let ret = type_for_adt(db, def.parent.into()).subst(&substs); - FnSig::from_params_and_return(params, ret) + let num_binders = generics.len(); + Binders::new(num_binders, FnSig::from_params_and_return(params, ret)) } /// Build the type of a tuple enum variant constructor. -fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId) -> Ty { +fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId) -> Binders { let enum_data = db.enum_data(def.parent); let var_data = &enum_data.variants[def.local_id].variant_data; if var_data.is_unit() { return type_for_adt(db, def.parent.into()); // Unit variant } let generics = generics(db, def.parent.into()); - let substs = Substs::identity(&generics); - Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs) + let substs = Substs::bound_vars(&generics); + Binders::new(substs.len(), Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs)) } -fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { +fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Binders { let generics = generics(db, adt.into()); - Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics)) + let substs = Substs::bound_vars(&generics); + Binders::new(substs.len(), Ty::apply(TypeCtor::Adt(adt), substs)) } -fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { +fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Binders { let generics = generics(db, t.into()); let resolver = t.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Variable); let type_ref = &db.type_alias_data(t).type_ref; - let substs = Substs::identity(&generics); + let substs = Substs::bound_vars(&generics); let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); - inner.subst(&substs) + Binders::new(substs.len(), inner) } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -797,19 +819,20 @@ impl_froms!(ValueTyDefId: FunctionId, StructId, EnumVariantId, ConstId, StaticId /// `struct Foo(usize)`, we have two types: The type of the struct itself, and /// the constructor function `(usize) -> Foo` which lives in the values /// namespace. -pub(crate) fn ty_query(db: &impl HirDatabase, def: TyDefId) -> Ty { +pub(crate) fn ty_query(db: &impl HirDatabase, def: TyDefId) -> Binders { match def { - TyDefId::BuiltinType(it) => type_for_builtin(it), + TyDefId::BuiltinType(it) => Binders::new(0, type_for_builtin(it)), TyDefId::AdtId(it) => type_for_adt(db, it), TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), } } -pub(crate) fn ty_recover(_db: &impl HirDatabase, _cycle: &[String], _def: &TyDefId) -> Ty { - Ty::Unknown +pub(crate) fn ty_recover(_db: &impl HirDatabase, _cycle: &[String], _def: &TyDefId) -> Binders { + // TODO still need correct number of binders here + Binders::new(0, Ty::Unknown) } -pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { +pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Binders { match def { ValueTyDefId::FunctionId(it) => type_for_fn(db, it), ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), @@ -819,34 +842,30 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { } } -pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty { +pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Binders { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; - Ty::from_hir(&ctx, &impl_data.target_type) + let generics = generics(db, impl_id.into()); + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Variable); + Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) } pub(crate) fn impl_self_ty_recover( - _db: &impl HirDatabase, + db: &impl HirDatabase, _cycle: &[String], - _impl_id: &ImplId, -) -> Ty { - Ty::Unknown + impl_id: &ImplId, +) -> Binders { + let generics = generics(db, (*impl_id).into()); + Binders::new(generics.len(), Ty::Unknown) } pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - let ctx = TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: ImplTraitLoweringMode::Disallowed, - }; - let self_ty = db.impl_self_ty(impl_id); + let generics = generics(db, impl_id.into()); + let ctx = TyLoweringContext::new(db, &resolver); + let self_ty = db.impl_self_ty(impl_id).subst(&Substs::identity(&generics)); let target_trait = impl_data.target_trait.as_ref()?; TraitRef::from_hir(&ctx, target_trait, Some(self_ty.clone())) } diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 5bacbbd7c7d..eab2149dc61 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -65,7 +65,7 @@ impl CrateImplBlocks { } None => { let self_ty = db.impl_self_ty(impl_id); - if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) { + if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) { res.impls.entry(self_ty_fp).or_default().push(impl_id); } } @@ -496,7 +496,7 @@ fn transform_receiver_ty( AssocContainerId::ContainerId(_) => unreachable!(), }; let sig = db.callable_item_signature(function_id.into()); - Some(sig.params()[0].clone().subst(&substs)) + Some(sig.value.params()[0].clone().subst_bound_vars(&substs)) } pub fn implements_trait( diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index fdab9c187f4..f1238506b83 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1220,7 +1220,7 @@ fn test() { } #[test] -fn infer_impl_generics() { +fn infer_impl_generics_basic() { assert_snapshot!( infer(r#" struct A { diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 314a3241f9d..f116b95e769 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use hir_def::{ adt::VariantData, db::DefDatabase, - generics::{GenericParams, TypeParamData}, + generics::{GenericParams, TypeParamData, TypeParamProvenance}, path::Path, resolver::{HasResolver, TypeNs}, type_ref::TypeRef, @@ -117,19 +117,31 @@ impl Generics { pub(crate) fn len(&self) -> usize { self.len_split().0 } + /// (total, parents, child) pub(crate) fn len_split(&self) -> (usize, usize, usize) { let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); let child = self.params.types.len(); (parent + child, parent, child) } + + /// (self, type param list, impl trait) + pub(crate) fn provenance_split(&self) -> (usize, usize, usize) { + let self_params = self.params.types.iter().filter(|(_, p)| p.provenance == TypeParamProvenance::TraitSelf).count(); + let list_params = self.params.types.iter().filter(|(_, p)| p.provenance == TypeParamProvenance::TypeParamList).count(); + let impl_trait_params = self.params.types.iter().filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait).count(); + (self_params, list_params, impl_trait_params) + } + pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 { self.find_param(param).0 } + pub(crate) fn param_name(&self, param: TypeParamId) -> Name { // FIXME make this return Option self.find_param(param).1.name.clone().unwrap_or_else(Name::missing) } + fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) { if param.parent == self.def { let (idx, (_local_id, data)) = self From 4789a993eb26963a2411dcc3041733a3b034634a Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 28 Jan 2020 21:42:58 +0100 Subject: [PATCH 06/25] Fix printing of function types --- crates/ra_hir_ty/src/lib.rs | 7 ++-- crates/ra_hir_ty/src/tests/coercion.rs | 26 ++++++------ .../ra_hir_ty/src/tests/method_resolution.rs | 42 +++++++++---------- crates/ra_hir_ty/src/tests/patterns.rs | 4 +- crates/ra_hir_ty/src/tests/regression.rs | 2 +- crates/ra_hir_ty/src/tests/simple.rs | 32 +++++++------- crates/ra_hir_ty/src/tests/traits.rs | 32 +++++++------- 7 files changed, 73 insertions(+), 72 deletions(-) diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 79084bb3e0e..1f0fd11280a 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -912,7 +912,8 @@ impl HirDisplay for ApplicationTy { write!(f, ") -> {}", sig.ret().display(f.db))?; } TypeCtor::FnDef(def) => { - let sig = f.db.callable_item_signature(def); + let sig = f.db.callable_item_signature(def) + .subst(&self.parameters); let name = match def { CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), @@ -933,8 +934,8 @@ impl HirDisplay for ApplicationTy { write!(f, ">")?; } write!(f, "(")?; - f.write_joined(sig.value.params(), ", ")?; - write!(f, ") -> {}", sig.value.ret().display(f.db))?; + f.write_joined(sig.params(), ", ")?; + write!(f, ") -> {}", sig.ret().display(f.db))?; } TypeCtor::Adt(def_id) => { let name = match def_id { diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 76a1b46c02c..fc5ef36a59f 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -75,7 +75,7 @@ fn test2() { [124; 131) 'loop {}': ! [129; 131) '{}': () [160; 173) '{ gen() }': *mut [U] - [166; 169) 'gen': fn gen() -> *mut [T; _] + [166; 169) 'gen': fn gen() -> *mut [U; _] [166; 171) 'gen()': *mut [U; _] [186; 420) '{ ...rr); }': () [196; 199) 'arr': &[u8; _] @@ -85,14 +85,14 @@ fn test2() { [227; 228) 'a': &[u8] [237; 240) 'arr': &[u8; _] [250; 251) 'b': u8 - [254; 255) 'f': fn f(&[T]) -> T + [254; 255) 'f': fn f(&[u8]) -> u8 [254; 260) 'f(arr)': u8 [256; 259) 'arr': &[u8; _] [270; 271) 'c': &[u8] [280; 287) '{ arr }': &[u8] [282; 285) 'arr': &[u8; _] [297; 298) 'd': u8 - [301; 302) 'g': fn g(S<&[T]>) -> T + [301; 302) 'g': fn g(S<&[u8]>) -> u8 [301; 316) 'g(S { a: arr })': u8 [303; 315) 'S { a: arr }': S<&[u8]> [310; 313) 'arr': &[u8; _] @@ -164,15 +164,15 @@ fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { [400; 401) 'c': C<[u8; _]> [415; 481) '{ ...(c); }': () [425; 426) 'd': A<[{unknown}]> - [429; 433) 'foo1': fn foo1<{unknown}>(A<[T]>) -> A<[T]> + [429; 433) 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> [429; 436) 'foo1(a)': A<[{unknown}]> [434; 435) 'a': A<[u8; _]> [446; 447) 'e': B<[u8]> - [450; 454) 'foo2': fn foo2(B<[T]>) -> B<[T]> + [450; 454) 'foo2': fn foo2(B<[u8]>) -> B<[u8]> [450; 457) 'foo2(b)': B<[u8]> [455; 456) 'b': B<[u8; _]> [467; 468) 'f': C<[u8]> - [471; 475) 'foo3': fn foo3(C<[T]>) -> C<[T]> + [471; 475) 'foo3': fn foo3(C<[u8]>) -> C<[u8]> [471; 478) 'foo3(c)': C<[u8]> [476; 477) 'c': C<[u8; _]> "### @@ -202,7 +202,7 @@ fn test() { [64; 123) 'if tru... }': &[i32] [67; 71) 'true': bool [72; 97) '{ ... }': &[i32] - [82; 85) 'foo': fn foo(&[T]) -> &[T] + [82; 85) 'foo': fn foo(&[i32]) -> &[i32] [82; 91) 'foo(&[1])': &[i32] [86; 90) '&[1]': &[i32; _] [87; 90) '[1]': [i32; _] @@ -242,7 +242,7 @@ fn test() { [83; 86) '[1]': [i32; _] [84; 85) '1': i32 [98; 123) '{ ... }': &[i32] - [108; 111) 'foo': fn foo(&[T]) -> &[T] + [108; 111) 'foo': fn foo(&[i32]) -> &[i32] [108; 117) 'foo(&[1])': &[i32] [112; 116) '&[1]': &[i32; _] [113; 116) '[1]': [i32; _] @@ -275,7 +275,7 @@ fn test(i: i32) { [70; 147) 'match ... }': &[i32] [76; 77) 'i': i32 [88; 89) '2': i32 - [93; 96) 'foo': fn foo(&[T]) -> &[T] + [93; 96) 'foo': fn foo(&[i32]) -> &[i32] [93; 102) 'foo(&[2])': &[i32] [97; 101) '&[2]': &[i32; _] [98; 101) '[2]': [i32; _] @@ -320,7 +320,7 @@ fn test(i: i32) { [94; 97) '[1]': [i32; _] [95; 96) '1': i32 [107; 108) '2': i32 - [112; 115) 'foo': fn foo(&[T]) -> &[T] + [112; 115) 'foo': fn foo(&[i32]) -> &[i32] [112; 121) 'foo(&[2])': &[i32] [116; 120) '&[2]': &[i32; _] [117; 120) '[2]': [i32; _] @@ -438,16 +438,16 @@ fn test() { [43; 45) '*x': T [44; 45) 'x': &T [58; 127) '{ ...oo); }': () - [64; 73) 'takes_ref': fn takes_ref(&T) -> T + [64; 73) 'takes_ref': fn takes_ref(&Foo) -> Foo [64; 79) 'takes_ref(&Foo)': Foo [74; 78) '&Foo': &Foo [75; 78) 'Foo': Foo - [85; 94) 'takes_ref': fn takes_ref<&Foo>(&T) -> T + [85; 94) 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo [85; 101) 'takes_...&&Foo)': &Foo [95; 100) '&&Foo': &&Foo [96; 100) '&Foo': &Foo [97; 100) 'Foo': Foo - [107; 116) 'takes_ref': fn takes_ref<&&Foo>(&T) -> T + [107; 116) 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo [107; 124) 'takes_...&&Foo)': &&Foo [117; 123) '&&&Foo': &&&Foo [118; 123) '&&Foo': &&Foo diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index ce9a06fde4b..6c7f6706a2d 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -27,7 +27,7 @@ fn test() { [66; 73) 'loop {}': ! [71; 73) '{}': () [133; 160) '{ ...o"); }': () - [139; 149) '<[_]>::foo': fn foo(&[T]) -> T + [139; 149) '<[_]>::foo': fn foo(&[u8]) -> u8 [139; 157) '<[_]>:..."foo")': u8 [150; 156) 'b"foo"': &[u8] "### @@ -175,7 +175,7 @@ fn test() { [98; 101) 'val': T [123; 155) '{ ...32); }': () [133; 134) 'a': Gen - [137; 146) 'Gen::make': fn make(T) -> Gen + [137; 146) 'Gen::make': fn make(u32) -> Gen [137; 152) 'Gen::make(0u32)': Gen [147; 151) '0u32': u32 "### @@ -206,7 +206,7 @@ fn test() { [95; 98) '{ }': () [118; 146) '{ ...e(); }': () [128; 129) 'a': Gen - [132; 141) 'Gen::make': fn make() -> Gen + [132; 141) 'Gen::make': fn make() -> Gen [132; 143) 'Gen::make()': Gen "### ); @@ -260,7 +260,7 @@ fn test() { [91; 94) '{ }': () [114; 149) '{ ...e(); }': () [124; 125) 'a': Gen - [128; 144) 'Gen::<...::make': fn make() -> Gen + [128; 144) 'Gen::<...::make': fn make() -> Gen [128; 146) 'Gen::<...make()': Gen "### ); @@ -291,7 +291,7 @@ fn test() { [117; 120) '{ }': () [140; 180) '{ ...e(); }': () [150; 151) 'a': Gen - [154; 175) 'Gen::<...::make': fn make() -> Gen + [154; 175) 'Gen::<...::make': fn make() -> Gen [154; 177) 'Gen::<...make()': Gen "### ); @@ -475,7 +475,7 @@ fn test() { @r###" [33; 37) 'self': &Self [102; 127) '{ ...d(); }': () - [108; 109) 'S': S(T) -> S + [108; 109) 'S': S(u32) -> S [108; 115) 'S(1u32)': S [108; 124) 'S(1u32...thod()': u32 [110; 114) '1u32': u32 @@ -501,13 +501,13 @@ fn test() { @r###" [87; 193) '{ ...t(); }': () [97; 99) 's1': S - [105; 121) 'Defaul...efault': fn default() -> Self + [105; 121) 'Defaul...efault': fn default() -> S [105; 123) 'Defaul...ault()': S [133; 135) 's2': S - [138; 148) 'S::default': fn default() -> Self + [138; 148) 'S::default': fn default() -> S [138; 150) 'S::default()': S [160; 162) 's3': S - [165; 188) '() -> Self + [165; 188) '() -> S [165; 190) '() -> T + [141; 148) 'S::make': fn make() -> u32 [141; 150) 'S::make()': u32 [160; 161) 'b': u64 - [164; 178) 'G::::make': fn make, u64>() -> T + [164; 178) 'G::::make': fn make, u64>() -> u64 [164; 180) 'G::, f64>() -> T + [199; 206) 'G::make': fn make, f64>() -> f64 [199; 208) 'G::make()': f64 "### ); @@ -567,19 +567,19 @@ fn test() { @r###" [135; 313) '{ ...e(); }': () [145; 146) 'a': (u32, i64) - [149; 163) 'S::make::': fn make() -> (T, U) + [149; 163) 'S::make::': fn make() -> (u32, i64) [149; 165) 'S::mak...i64>()': (u32, i64) [175; 176) 'b': (u32, i64) - [189; 196) 'S::make': fn make() -> (T, U) + [189; 196) 'S::make': fn make() -> (u32, i64) [189; 198) 'S::make()': (u32, i64) [208; 209) 'c': (u32, i64) - [212; 233) 'G::': fn make, u32, i64>() -> (T, U) + [212; 233) 'G::': fn make, u32, i64>() -> (u32, i64) [212; 235) 'G::()': (u32, i64) [245; 246) 'd': (u32, i64) - [259; 273) 'G::make::': fn make, u32, i64>() -> (T, U) + [259; 273) 'G::make::': fn make, u32, i64>() -> (u32, i64) [259; 275) 'G::mak...i64>()': (u32, i64) [285; 286) 'e': (u32, i64) - [301; 308) 'G::make': fn make, u32, i64>() -> (T, U) + [301; 308) 'G::make': fn make, u32, i64>() -> (u32, i64) [301; 310) 'G::make()': (u32, i64) "### ); @@ -601,7 +601,7 @@ fn test() { @r###" [101; 127) '{ ...e(); }': () [111; 112) 'a': (S, i64) - [115; 122) 'S::make': fn make, i64>() -> (Self, T) + [115; 122) 'S::make': fn make, i64>() -> (S, i64) [115; 124) 'S::make()': (S, i64) "### ); @@ -625,10 +625,10 @@ fn test() { @r###" [131; 203) '{ ...e(); }': () [141; 142) 'a': (S, i64) - [158; 165) 'S::make': fn make, i64>() -> (Self, T) + [158; 165) 'S::make': fn make, i64>() -> (S, i64) [158; 167) 'S::make()': (S, i64) [177; 178) 'b': (S, i32) - [191; 198) 'S::make': fn make, i32>() -> (Self, T) + [191; 198) 'S::make': fn make, i32>() -> (S, i32) [191; 200) 'S::make()': (S, i32) "### ); @@ -728,7 +728,7 @@ fn test() { [157; 158) 'S': S [157; 165) 'S.into()': u64 [175; 176) 'z': u64 - [179; 196) 'Into::...::into': fn into(Self) -> T + [179; 196) 'Into::...::into': fn into(S) -> u64 [179; 199) 'Into::...nto(S)': u64 [197; 198) 'S': S "### diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index cb3890b4239..e25d6dbc43d 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs @@ -96,13 +96,13 @@ fn test() { [38; 42) 'A(n)': A [40; 41) 'n': &i32 [45; 50) '&A(1)': &A - [46; 47) 'A': A(T) -> A + [46; 47) 'A': A(i32) -> A [46; 50) 'A(1)': A [48; 49) '1': i32 [60; 64) 'A(n)': A [62; 63) 'n': &mut i32 [67; 76) '&mut A(1)': &mut A - [72; 73) 'A': A(T) -> A + [72; 73) 'A': A(i32) -> A [72; 76) 'A(1)': A [74; 75) '1': i32 "### diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index 02bab6dbe08..14c8ed3a9b7 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs @@ -346,7 +346,7 @@ pub fn main_loop() { @r###" [144; 146) '{}': () [169; 198) '{ ...t(); }': () - [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet + [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher> [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher> "### ); diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index f1238506b83..b08355227d1 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -754,15 +754,15 @@ fn test() { [289; 295) 'self.0': T [315; 353) '{ ...))); }': () [325; 326) 't': &i32 - [329; 335) 'A::foo': fn foo(&A) -> &T + [329; 335) 'A::foo': fn foo(&A) -> &i32 [329; 350) 'A::foo...42))))': &i32 [336; 349) '&&B(B(A(42)))': &&B>> [337; 349) '&B(B(A(42)))': &B>> - [338; 339) 'B': B>>(T) -> B + [338; 339) 'B': B>>(B>) -> B>> [338; 349) 'B(B(A(42)))': B>> - [340; 341) 'B': B>(T) -> B + [340; 341) 'B': B>(A) -> B> [340; 348) 'B(A(42))': B> - [342; 343) 'A': A(T) -> A + [342; 343) 'A': A(i32) -> A [342; 347) 'A(42)': A [344; 346) '42': i32 "### @@ -817,16 +817,16 @@ fn test(a: A) { [326; 327) 'a': A [337; 383) '{ ...))); }': () [347; 348) 't': &i32 - [351; 352) 'A': A(*mut T) -> A + [351; 352) 'A': A(*mut i32) -> A [351; 365) 'A(0 as *mut _)': A [351; 380) 'A(0 as...B(a)))': &i32 [353; 354) '0': i32 [353; 364) '0 as *mut _': *mut i32 [370; 379) '&&B(B(a))': &&B>> [371; 379) '&B(B(a))': &B>> - [372; 373) 'B': B>>(T) -> B + [372; 373) 'B': B>>(B>) -> B>> [372; 379) 'B(B(a))': B>> - [374; 375) 'B': B>(T) -> B + [374; 375) 'B': B>(A) -> B> [374; 378) 'B(a)': B> [376; 377) 'a': A "### @@ -1205,14 +1205,14 @@ fn test() { [21; 26) '{ t }': T [23; 24) 't': T [38; 98) '{ ...(1); }': () - [44; 46) 'id': fn id(T) -> T + [44; 46) 'id': fn id(u32) -> u32 [44; 52) 'id(1u32)': u32 [47; 51) '1u32': u32 - [58; 68) 'id::': fn id(T) -> T + [58; 68) 'id::': fn id(i128) -> i128 [58; 71) 'id::(1)': i128 [69; 70) '1': i128 [81; 82) 'x': u64 - [90; 92) 'id': fn id(T) -> T + [90; 92) 'id': fn id(u64) -> u64 [90; 95) 'id(1)': u64 [93; 94) '1': u64 "### @@ -1349,16 +1349,16 @@ fn test() -> i128 { [146; 147) 'x': i128 [150; 151) '1': i128 [162; 163) 'y': i128 - [166; 168) 'id': fn id(T) -> T + [166; 168) 'id': fn id(i128) -> i128 [166; 171) 'id(x)': i128 [169; 170) 'x': i128 [182; 183) 'a': A [186; 200) 'A { x: id(y) }': A - [193; 195) 'id': fn id(T) -> T + [193; 195) 'id': fn id(i128) -> i128 [193; 198) 'id(y)': i128 [196; 197) 'y': i128 [211; 212) 'z': i128 - [215; 217) 'id': fn id(T) -> T + [215; 217) 'id': fn id(i128) -> i128 [215; 222) 'id(a.x)': i128 [218; 219) 'a': A [218; 221) 'a.x': i128 @@ -1502,14 +1502,14 @@ fn test() { [78; 158) '{ ...(1); }': () [88; 89) 'y': u32 [92; 97) '10u32': u32 - [103; 105) 'id': fn id(T) -> T + [103; 105) 'id': fn id(u32) -> u32 [103; 108) 'id(y)': u32 [106; 107) 'y': u32 [118; 119) 'x': bool - [128; 133) 'clone': fn clone(&T) -> T + [128; 133) 'clone': fn clone(&bool) -> bool [128; 136) 'clone(z)': bool [134; 135) 'z': &bool - [142; 152) 'id::': fn id(T) -> T + [142; 152) 'id::': fn id(i128) -> i128 [142; 155) 'id::(1)': i128 [153; 154) '1': i128 "### diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 764ab280017..eae6e96816c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -261,10 +261,10 @@ fn test() { [92; 94) '{}': () [105; 144) '{ ...(s); }': () [115; 116) 's': S - [119; 120) 'S': S(T) -> S + [119; 120) 'S': S(u32) -> S [119; 129) 'S(unknown)': S [121; 128) 'unknown': u32 - [135; 138) 'foo': fn foo>(T) -> () + [135; 138) 'foo': fn foo>(S) -> () [135; 141) 'foo(s)': () [139; 140) 's': S "### @@ -289,11 +289,11 @@ fn test() { [98; 100) '{}': () [111; 163) '{ ...(s); }': () [121; 122) 's': S - [125; 126) 'S': S(T) -> S + [125; 126) 'S': S(u32) -> S [125; 135) 'S(unknown)': S [127; 134) 'unknown': u32 [145; 146) 'x': u32 - [154; 157) 'foo': fn foo>(T) -> U + [154; 157) 'foo': fn foo>(S) -> u32 [154; 160) 'foo(s)': u32 [158; 159) 's': S "### @@ -1066,26 +1066,26 @@ fn test>(x: T, y: impl Trait) { [296; 299) 'get': fn get(T) -> ::Type [296; 302) 'get(x)': {unknown} [300; 301) 'x': T - [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U + [308; 312) 'get2': fn get2<{unknown}, T>(T) -> {unknown} [308; 315) 'get2(x)': {unknown} [313; 314) 'x': T - [321; 324) 'get': fn get>(T) -> ::Type + [321; 324) 'get': fn get>(impl Trait) -> as Trait>::Type [321; 327) 'get(y)': {unknown} [325; 326) 'y': impl Trait - [333; 337) 'get2': fn get2<{unknown}, impl Trait>(T) -> U + [333; 337) 'get2': fn get2<{unknown}, impl Trait>(impl Trait) -> {unknown} [333; 340) 'get2(y)': {unknown} [338; 339) 'y': impl Trait - [346; 349) 'get': fn get>(T) -> ::Type + [346; 349) 'get': fn get>(S) -> as Trait>::Type [346; 357) 'get(set(S))': u64 - [350; 353) 'set': fn set>(T) -> T + [350; 353) 'set': fn set>(S) -> S [350; 356) 'set(S)': S [354; 355) 'S': S - [363; 367) 'get2': fn get2>(T) -> U + [363; 367) 'get2': fn get2>(S) -> u64 [363; 375) 'get2(set(S))': u64 - [368; 371) 'set': fn set>(T) -> T + [368; 371) 'set': fn set>(S) -> S [368; 374) 'set(S)': S [372; 373) 'S': S - [381; 385) 'get2': fn get2>(T) -> U + [381; 385) 'get2': fn get2>(S) -> str [381; 395) 'get2(S::)': str [386; 394) 'S::': S "### @@ -1258,9 +1258,9 @@ fn test() { [157; 160) '{t}': T [158; 159) 't': T [259; 280) '{ ...S)); }': () - [265; 269) 'get2': fn get2>(T) -> U + [265; 269) 'get2': fn get2>(S) -> u64 [265; 277) 'get2(set(S))': u64 - [270; 273) 'set': fn set>(T) -> T + [270; 273) 'set': fn set>(S) -> S [270; 276) 'set(S)': S [274; 275) 'S': S "### @@ -1432,7 +1432,7 @@ fn test() { [340; 342) '{}': () [356; 515) '{ ... S); }': () [366; 368) 'x1': u64 - [371; 375) 'foo1': fn foo1 u64>(T, F) -> U + [371; 375) 'foo1': fn foo1 u64>(S, |S| -> u64) -> u64 [371; 394) 'foo1(S...hod())': u64 [376; 377) 'S': S [379; 393) '|s| s.method()': |S| -> u64 @@ -1440,7 +1440,7 @@ fn test() { [383; 384) 's': S [383; 393) 's.method()': u64 [404; 406) 'x2': u64 - [409; 413) 'foo2': fn foo2 u64>(F, T) -> U + [409; 413) 'foo2': fn foo2 u64>(|S| -> u64, S) -> u64 [409; 432) 'foo2(|...(), S)': u64 [414; 428) '|s| s.method()': |S| -> u64 [415; 416) 's': S From a5554dcb17defd2cda729ce0ae732062990391db Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 29 Jan 2020 21:30:24 +0100 Subject: [PATCH 07/25] Fix enum constructors --- crates/ra_hir_ty/src/lower.rs | 10 ++++------ crates/ra_hir_ty/src/tests/simple.rs | 8 ++++---- crates/ra_hir_ty/src/tests/traits.rs | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 006101f2f7c..25c894c9597 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -729,14 +729,12 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId let var_data = &enum_data.variants[def.local_id]; let fields = var_data.variant_data.fields(); let resolver = def.parent.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); - let generics = generics(db, def.parent.into()); - let substs = Substs::bound_vars(&generics); - let ret = type_for_adt(db, def.parent.into()).subst(&substs); - let num_binders = generics.len(); - Binders::new(num_binders, FnSig::from_params_and_return(params, ret)) + let ret = type_for_adt(db, def.parent.into()); + Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) } /// Build the type of a tuple enum variant constructor. diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index b08355227d1..3803f5938cf 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1169,16 +1169,16 @@ fn test() { "#), @r###" [76; 184) '{ ...one; }': () - [82; 83) 'A': A(T) -> A + [82; 83) 'A': A(i32) -> A [82; 87) 'A(42)': A [84; 86) '42': i32 - [93; 94) 'A': A(T) -> A + [93; 94) 'A': A(u128) -> A [93; 102) 'A(42u128)': A [95; 101) '42u128': u128 - [108; 112) 'Some': Some<&str>(T) -> Option + [108; 112) 'Some': Some<&str>(&str) -> Option<&str> [108; 117) 'Some("x")': Option<&str> [113; 116) '"x"': &str - [123; 135) 'Option::Some': Some<&str>(T) -> Option + [123; 135) 'Option::Some': Some<&str>(&str) -> Option<&str> [123; 140) 'Option...e("x")': Option<&str> [136; 139) '"x"': &str [146; 150) 'None': Option<{unknown}> diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index eae6e96816c..9ff396ad568 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1322,7 +1322,7 @@ fn test() { [173; 175) '{}': () [189; 308) '{ ... 1); }': () [199; 200) 'x': Option - [203; 215) 'Option::Some': Some(T) -> Option + [203; 215) 'Option::Some': Some(u32) -> Option [203; 221) 'Option...(1u32)': Option [216; 220) '1u32': u32 [227; 228) 'x': Option From a9430865b319ab2fc28602fe98df21146e54b7bf Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 29 Jan 2020 22:32:37 +0100 Subject: [PATCH 08/25] Fix crash --- crates/ra_hir_ty/src/lower.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 25c894c9597..459b962809f 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -140,10 +140,13 @@ impl Ty { ImplTraitLoweringMode::Variable => { let idx = ctx.impl_trait_counter.get(); ctx.impl_trait_counter.set(idx + 1); - let generics = - generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); - let (self_params, list_params, impl_trait_params) = generics.provenance_split(); - assert!((idx as usize) < impl_trait_params); + let (self_params, list_params, _impl_trait_params) = if let Some(def) = ctx.resolver.generic_def() { + let generics = generics(ctx.db, def); + generics.provenance_split() + } else { + (0, 0, 0) + }; + // assert!((idx as usize) < impl_trait_params); // TODO return position impl trait Ty::Bound(idx as u32 + self_params as u32 + list_params as u32) } ImplTraitLoweringMode::Disallowed => { From dbc14f9d570e5bc1ddae05e9ccd8f163082b3cac Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 31 Jan 2020 15:17:48 +0100 Subject: [PATCH 09/25] First stab at desugaring bounds for APIT --- crates/ra_hir_def/src/generics.rs | 27 +++++++++++++++++++++++---- crates/ra_hir_ty/src/lower.rs | 29 ++++++++++++++++++++++++++--- crates/ra_hir_ty/src/utils.rs | 10 +++++++--- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 7553d8a8719..e4e616519ba 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -53,10 +53,17 @@ pub struct GenericParams { /// associated type bindings like `Iterator`. #[derive(Clone, PartialEq, Eq, Debug)] pub struct WherePredicate { - pub type_ref: TypeRef, + pub target: WherePredicateTarget, pub bound: TypeBound, } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum WherePredicateTarget { + TypeRef(TypeRef), + /// For desugared where predicates that can directly refer to a type param. + TypeParam(LocalTypeParamId) +} + type SourceMap = ArenaMap>; impl GenericParams { @@ -190,18 +197,24 @@ impl GenericParams { return; } let bound = TypeBound::from_ast(bound); - self.where_predicates.push(WherePredicate { type_ref, bound }); + self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); } fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { type_ref.walk(&mut |type_ref| { - if let TypeRef::ImplTrait(_) = type_ref { + if let TypeRef::ImplTrait(bounds) = type_ref { let param = TypeParamData { name: None, default: None, provenance: TypeParamProvenance::ArgumentImplTrait, }; - let _param_id = self.types.alloc(param); + let param_id = self.types.alloc(param); + for bound in bounds { + self.where_predicates.push(WherePredicate { + target: WherePredicateTarget::TypeParam(param_id), + bound: bound.clone() + }); + } } }); } @@ -211,6 +224,12 @@ impl GenericParams { .iter() .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) } + + pub fn find_trait_self_param(&self) -> Option { + self.types + .iter() + .find_map(|(id, p)| if p.provenance == TypeParamProvenance::TraitSelf { Some(id) } else { None }) + } } impl HasChildSource for GenericDefId { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 459b962809f..f1a11e07351 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, - generics::WherePredicate, + generics::{WherePredicateTarget, WherePredicate}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, @@ -505,7 +505,22 @@ impl GenericPredicate { ctx: &'a TyLoweringContext<'a, impl HirDatabase>, where_predicate: &'a WherePredicate, ) -> impl Iterator + 'a { - let self_ty = Ty::from_hir(ctx, &where_predicate.type_ref); + let self_ty = match &where_predicate.target { + WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), + WherePredicateTarget::TypeParam(param_id) => { + let generic_def = ctx.resolver.generic_def().expect("generics in scope"); + let generics = generics(ctx.db, generic_def); + let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; + let idx = generics.param_idx(param_id); + match ctx.type_param_mode { + TypeParamLoweringMode::Placeholder => { + let name = generics.param_name(param_id); + Ty::Param { idx, name } + }, + TypeParamLoweringMode::Variable => Ty::Bound(idx), + } + }, + }; GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty) } @@ -595,10 +610,18 @@ pub(crate) fn generic_predicates_for_param_query( ) -> Arc<[GenericPredicate]> { let resolver = def.resolver(db); let ctx = TyLoweringContext::new(db, &resolver); + let generics = generics(db, def); resolver .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them - .filter(|pred| Ty::from_hir_only_param(&ctx, &pred.type_ref) == Some(param_idx)) + .filter(|pred| match &pred.target { + WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_idx), + WherePredicateTarget::TypeParam(local_id) => { + let param_id = hir_def::TypeParamId { parent: def, local_id: *local_id }; + let idx = generics.param_idx(param_id); + idx == param_idx + } + }) .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect() } diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index f116b95e769..77b7de72971 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -12,6 +12,7 @@ use hir_def::{ AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, }; use hir_expand::name::{name, Name}; +use hir_def::generics::WherePredicateTarget; fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { let resolver = trait_.resolver(db); @@ -19,11 +20,14 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { // lifetime problems, but since there usually shouldn't be more than a // few direct traits this should be fine (we could even use some kind of // SmallVec if performance is a concern) - db.generic_params(trait_.into()) + let generic_params = db.generic_params(trait_.into()); + let trait_self = generic_params.find_trait_self_param(); + generic_params .where_predicates .iter() - .filter_map(|pred| match &pred.type_ref { - TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(), + .filter_map(|pred| match &pred.target { + WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => pred.bound.as_path(), + WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => pred.bound.as_path(), _ => None, }) .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { From 4a8279a21ad75ae2cb6d96746b8a880038ec0455 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 31 Jan 2020 15:34:43 +0100 Subject: [PATCH 10/25] Fix another test --- crates/ra_hir_ty/src/infer/path.rs | 6 +----- crates/ra_hir_ty/src/tests/method_resolution.rs | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 39aa346eb32..fcf13b0b313 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -177,13 +177,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { AssocItemId::ConstId(c) => ValueNs::ConstId(c), AssocItemId::TypeAliasId(_) => unreachable!(), }; - let substs = Substs::build_for_def(self.db, item) - .use_parent_substs(&trait_ref.substs) - .fill_with_params() - .build(); self.write_assoc_resolution(id, item); - Some((def, Some(substs))) + Some((def, Some(trait_ref.substs))) } fn resolve_ty_assoc_item( diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 6c7f6706a2d..446d1281362 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -651,10 +651,10 @@ fn test() { @r###" [107; 211) '{ ...>(); }': () [117; 118) 'a': (S, i64, u8) - [121; 150) '': fn make, i64, u8>() -> (Self, T, U) + [121; 150) '': fn make, i64, u8>() -> (S, i64, u8) [121; 152) '()': (S, i64, u8) [162; 163) 'b': (S, i64, u8) - [182; 206) 'Trait:...::': fn make, i64, u8>() -> (Self, T, U) + [182; 206) 'Trait:...::': fn make, i64, u8>() -> (S, i64, u8) [182; 208) 'Trait:...()': (S, i64, u8) "### ); From 33aa2f8e4f2b9c7c3a6b28427cb6d6f2aef7b802 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 31 Jan 2020 15:57:44 +0100 Subject: [PATCH 11/25] Fix assoc type selection --- crates/ra_hir_ty/src/lower.rs | 69 ++++++++++++++++------------ crates/ra_hir_ty/src/tests/traits.rs | 6 +-- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index f1a11e07351..5138019c73f 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, - generics::{WherePredicateTarget, WherePredicate}, + generics::{WherePredicate, WherePredicateTarget}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, @@ -27,8 +27,8 @@ use crate::{ all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, variant_data, }, - FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, - Ty, TypeCtor, PolyFnSig, Binders, + Binders, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, ProjectionTy, Substs, + TraitEnvironment, TraitRef, Ty, TypeCtor, }; #[derive(Debug)] @@ -62,7 +62,7 @@ impl<'a, DB: HirDatabase> TyLoweringContext<'a, DB> { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ImplTraitLoweringMode { /// `impl Trait` gets lowered into an opaque type that doesn't unify with /// anything except itself. This is used in places where values flow 'out', @@ -78,7 +78,7 @@ pub enum ImplTraitLoweringMode { Disallowed, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum TypeParamLoweringMode { Placeholder, Variable, @@ -140,12 +140,13 @@ impl Ty { ImplTraitLoweringMode::Variable => { let idx = ctx.impl_trait_counter.get(); ctx.impl_trait_counter.set(idx + 1); - let (self_params, list_params, _impl_trait_params) = if let Some(def) = ctx.resolver.generic_def() { - let generics = generics(ctx.db, def); - generics.provenance_split() - } else { - (0, 0, 0) - }; + let (self_params, list_params, _impl_trait_params) = + if let Some(def) = ctx.resolver.generic_def() { + let generics = generics(ctx.db, def); + generics.provenance_split() + } else { + (0, 0, 0) + }; // assert!((idx as usize) < impl_trait_params); // TODO return position impl trait Ty::Bound(idx as u32 + self_params as u32 + list_params as u32) } @@ -251,7 +252,7 @@ impl Ty { // FIXME: maybe return name in resolution? let name = generics.param_name(param_id); Ty::Param { idx, name } - }, + } TypeParamLoweringMode::Variable => Ty::Bound(idx), } } @@ -262,7 +263,7 @@ impl Ty { TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.impl_self_ty(impl_id).subst(&substs) - }, + } TypeNs::AdtSelfType(adt) => { let generics = generics(ctx.db, adt.into()); let substs = match ctx.type_param_mode { @@ -270,7 +271,7 @@ impl Ty { TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.ty(adt.into()).subst(&substs) - }, + } TypeNs::AdtId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), @@ -309,7 +310,8 @@ impl Ty { segment: PathSegment<'_>, ) -> Ty { let param_idx = match self_ty { - Ty::Param { idx, .. } => idx, + Ty::Param { idx, .. } if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => idx, + Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => idx, _ => return Ty::Unknown, // Error: Ambiguous associated type }; let def = match ctx.resolver.generic_def() { @@ -318,7 +320,14 @@ impl Ty { }; let predicates = ctx.db.generic_predicates_for_param(def.into(), param_idx); let traits_from_env = predicates.iter().filter_map(|pred| match pred { - GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_), + GenericPredicate::Implemented(tr) => { + if let Ty::Param { idx, .. } = tr.self_ty() { + if *idx == param_idx { + return Some(tr.trait_); + } + } + None + } _ => None, }); let traits = traits_from_env.flat_map(|t| all_super_traits(ctx.db, t)); @@ -516,10 +525,10 @@ impl GenericPredicate { TypeParamLoweringMode::Placeholder => { let name = generics.param_name(param_id); Ty::Param { idx, name } - }, + } TypeParamLoweringMode::Variable => Ty::Bound(idx), } - }, + } }; GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty) } @@ -615,7 +624,9 @@ pub(crate) fn generic_predicates_for_param_query( .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them .filter(|pred| match &pred.target { - WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_idx), + WherePredicateTarget::TypeRef(type_ref) => { + Ty::from_hir_only_param(&ctx, type_ref) == Some(param_idx) + } WherePredicateTarget::TypeParam(local_id) => { let param_id = hir_def::TypeParamId { parent: def, local_id: *local_id }; let idx = generics.param_idx(param_id); @@ -701,8 +712,8 @@ fn type_for_const(db: &impl HirDatabase, def: ConstId) -> Binders { let data = db.const_data(def); let generics = generics(db, def.into()); let resolver = def.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver) - .with_type_param_mode(TypeParamLoweringMode::Variable); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); Binders::new(generics.len(), Ty::from_hir(&ctx, &data.type_ref)) } @@ -731,8 +742,8 @@ fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> PolyFn let struct_data = db.struct_data(def.into()); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver) - .with_type_param_mode(TypeParamLoweringMode::Variable); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let ret = type_for_adt(db, def.into()); @@ -755,8 +766,8 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId let var_data = &enum_data.variants[def.local_id]; let fields = var_data.variant_data.fields(); let resolver = def.parent.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver) - .with_type_param_mode(TypeParamLoweringMode::Variable); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::>(); let ret = type_for_adt(db, def.parent.into()); @@ -784,8 +795,8 @@ fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Binders { fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Binders { let generics = generics(db, t.into()); let resolver = t.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver) - .with_type_param_mode(TypeParamLoweringMode::Variable); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); let type_ref = &db.type_alias_data(t).type_ref; let substs = Substs::bound_vars(&generics); let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); @@ -870,8 +881,8 @@ pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Bind let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); let generics = generics(db, impl_id.into()); - let ctx = TyLoweringContext::new(db, &resolver) - .with_type_param_mode(TypeParamLoweringMode::Variable); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) } diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 9ff396ad568..e2351ca983e 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -358,15 +358,15 @@ fn test() { [221; 223) '{}': () [234; 300) '{ ...(S); }': () [244; 245) 'x': u32 - [248; 252) 'foo1': fn foo1(T) -> ::Item + [248; 252) 'foo1': fn foo1(S) -> ::Item [248; 255) 'foo1(S)': u32 [253; 254) 'S': S [265; 266) 'y': u32 - [269; 273) 'foo2': fn foo2(T) -> ::Item + [269; 273) 'foo2': fn foo2(S) -> ::Item [269; 276) 'foo2(S)': u32 [274; 275) 'S': S [286; 287) 'z': u32 - [290; 294) 'foo3': fn foo3(T) -> ::Item + [290; 294) 'foo3': fn foo3(S) -> ::Item [290; 297) 'foo3(S)': u32 [295; 296) 'S': S "### From f8b7b64bce772f21124b4790538ca97418cc23ca Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 31 Jan 2020 16:05:58 +0100 Subject: [PATCH 12/25] WIP use params for APIT --- crates/ra_hir_ty/src/infer.rs | 2 +- crates/ra_hir_ty/src/lower.rs | 10 ++++++ crates/ra_hir_ty/src/tests/traits.rs | 53 ++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index f7ef09f0eea..0d65984eefb 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -480,7 +480,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn collect_fn(&mut self, data: &FunctionData) { let body = Arc::clone(&self.body); // avoid borrow checker problem for (type_ref, pat) in data.params.iter().zip(body.params.iter()) { - let ty = self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Opaque); + let ty = self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Param); self.infer_pat(*pat, &ty, BindingMode::default()); } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 5138019c73f..88d962b4760 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -30,6 +30,7 @@ use crate::{ Binders, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, }; +use hir_expand::name::Name; #[derive(Debug)] pub struct TyLoweringContext<'a, DB: HirDatabase> { @@ -69,6 +70,10 @@ pub enum ImplTraitLoweringMode { /// i.e. for arguments of the function we're currently checking, and return /// types of functions we're calling. Opaque, + /// `impl Trait` gets lowered into a type variable. Used for argument + /// position impl Trait currently, since it allows us to support that + /// without Chalk. + Param, /// `impl Trait` gets lowered into a variable that can unify with some /// type. This is used in places where values flow 'in', i.e. for arguments /// of functions we're calling, and the return type of the function we're @@ -137,6 +142,11 @@ impl Ty { .collect(); Ty::Opaque(predicates) } + ImplTraitLoweringMode::Param => { + let idx = ctx.impl_trait_counter.get(); + ctx.impl_trait_counter.set(idx + 1); + Ty::Param { idx: idx as u32, name: Name::missing() } + } ImplTraitLoweringMode::Variable => { let idx = ctx.impl_trait_counter.get(); ctx.impl_trait_counter.set(idx + 1); diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e2351ca983e..dc78e83cd2c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -849,6 +849,59 @@ fn test(t: T) { assert_eq!(t, "{unknown}"); } +#[test] +fn argument_impl_trait() { + assert_snapshot!( + infer_with_mismatches(r#" +trait Trait { + fn foo(&self) -> T; + fn foo2(&self) -> i64; +} +fn bar(impl Trait) {} +struct S(T); +impl Trait for S {} + +fn test(x: impl Trait, y: &impl Trait) { + x; + y; + let z = S(1); + bar(z); + x.foo(); + y.foo(); + z.foo(); + x.foo2(); + y.foo2(); + z.foo2(); +} +"#, true), + @r###" + [30; 34) 'self': &Self + [55; 59) 'self': &Self + [99; 101) '{}': () + [111; 112) 'x': impl Trait + [131; 132) 'y': &impl Trait + [152; 269) '{ ...2(); }': () + [158; 159) 'x': impl Trait + [165; 166) 'y': &impl Trait + [176; 177) 'z': impl Trait + [180; 183) 'bar': fn bar() -> impl Trait + [180; 185) 'bar()': impl Trait + [191; 192) 'x': impl Trait + [191; 198) 'x.foo()': u64 + [204; 205) 'y': &impl Trait + [204; 211) 'y.foo()': u64 + [217; 218) 'z': impl Trait + [217; 224) 'z.foo()': u64 + [230; 231) 'x': impl Trait + [230; 238) 'x.foo2()': i64 + [244; 245) 'y': &impl Trait + [244; 252) 'y.foo2()': i64 + [258; 259) 'z': impl Trait + [258; 266) 'z.foo2()': i64 + "### + ); +} + #[test] #[ignore] fn impl_trait() { From ed25cf70d5e0df9c7a33deb503ea14c2d97bd7a7 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 31 Jan 2020 16:52:43 +0100 Subject: [PATCH 13/25] Change Ty::Param to contain param ID --- crates/ra_hir_ty/src/db.rs | 17 ++- crates/ra_hir_ty/src/infer/coerce.rs | 16 +-- crates/ra_hir_ty/src/infer/expr.rs | 5 +- crates/ra_hir_ty/src/infer/pat.rs | 7 +- crates/ra_hir_ty/src/lib.rs | 49 ++++---- crates/ra_hir_ty/src/lower.rs | 108 ++++++++++-------- crates/ra_hir_ty/src/method_resolution.rs | 2 +- .../ra_hir_ty/src/tests/method_resolution.rs | 2 +- crates/ra_hir_ty/src/tests/traits.rs | 3 +- crates/ra_hir_ty/src/traits/chalk.rs | 24 ++-- crates/ra_hir_ty/src/utils.rs | 30 ++--- 11 files changed, 136 insertions(+), 127 deletions(-) diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index fea122a8b96..7684ade0681 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -3,10 +3,10 @@ use std::sync::Arc; use hir_def::{ - db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalStructFieldId, TraitId, VariantId, + db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalStructFieldId, TraitId, VariantId, TypeParamId, }; use ra_arena::map::ArenaMap; -use ra_db::{salsa, CrateId}; +use ra_db::{impl_intern_key, salsa, CrateId}; use ra_prof::profile; use crate::{ @@ -37,10 +37,10 @@ pub trait HirDatabase: DefDatabase { fn impl_self_ty(&self, def: ImplId) -> Binders; #[salsa::invoke(crate::lower::impl_trait_query)] - fn impl_trait(&self, def: ImplId) -> Option; + fn impl_trait(&self, def: ImplId) -> Option>; #[salsa::invoke(crate::lower::field_types_query)] - fn field_types(&self, var: VariantId) -> Arc>; + fn field_types(&self, var: VariantId) -> Arc>>; #[salsa::invoke(crate::callable_item_sig)] fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; @@ -49,8 +49,7 @@ pub trait HirDatabase: DefDatabase { #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] fn generic_predicates_for_param( &self, - def: GenericDefId, - param_idx: u32, + param_id: TypeParamId, ) -> Arc<[GenericPredicate]>; #[salsa::invoke(crate::lower::generic_predicates_query)] @@ -77,6 +76,8 @@ pub trait HirDatabase: DefDatabase { #[salsa::interned] fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; #[salsa::interned] + fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; + #[salsa::interned] fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; #[salsa::interned] fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; @@ -117,3 +118,7 @@ fn infer(db: &impl HirDatabase, def: DefWithBodyId) -> Arc { fn hir_database_is_object_safe() { fn _assert_object_safe(_: &dyn HirDatabase) {} } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct GlobalTypeParamId(salsa::InternId); +impl_intern_key!(GlobalTypeParamId); diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 83c0c2c3f33..2a95678984e 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -57,8 +57,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let trait_ref = db.impl_trait(impl_id)?; // `CoerseUnsized` has one generic parameter for the target type. - let cur_from_ty = trait_ref.substs.0.get(0)?; - let cur_to_ty = trait_ref.substs.0.get(1)?; + let cur_from_ty = trait_ref.value.substs.0.get(0)?; + let cur_to_ty = trait_ref.value.substs.0.get(1)?; match (&cur_from_ty, cur_to_ty) { (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => { @@ -66,8 +66,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // This works for smart-pointer-like coercion, which covers all impls from std. st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| { match (ty1, ty2) { - (Ty::Param { idx: p1, .. }, Ty::Param { idx: p2, .. }) - if p1 != p2 => + (Ty::Bound(idx1), Ty::Bound(idx2)) + if idx1 != idx2 => { Some(((*ctor1, *ctor2), i)) } @@ -256,8 +256,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let unsize_generic_index = { let mut index = None; let mut multiple_param = false; - field_tys[last_field_id].walk(&mut |ty| match ty { - &Ty::Param { idx, .. } => { + field_tys[last_field_id].value.walk(&mut |ty| match ty { + &Ty::Bound(idx) => { if index.is_none() { index = Some(idx); } else if Some(idx) != index { @@ -276,8 +276,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // Check other fields do not involve it. let mut multiple_used = false; fields.for_each(|(field_id, _data)| { - field_tys[field_id].walk(&mut |ty| match ty { - &Ty::Param { idx, .. } if idx == unsize_generic_index => { + field_tys[field_id].value.walk(&mut |ty| match ty { + &Ty::Bound(idx) if idx == unsize_generic_index => { multiple_used = true } _ => {} diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index e1fdb356df8..8b83784993d 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -236,8 +236,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.result.record_field_resolutions.insert(field.expr, field_def); } let field_ty = field_def - .map_or(Ty::Unknown, |it| field_types[it.local_id].clone()) - .subst(&substs); + .map_or(Ty::Unknown, |it| field_types[it.local_id].clone().subst(&substs)); self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); } if let Some(expr) = spread { @@ -686,7 +685,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if let TypeCtor::FnDef(def) = a_ty.ctor { let generic_predicates = self.db.generic_predicates(def.into()); for predicate in generic_predicates.iter() { - let predicate = predicate.clone().subst(&a_ty.parameters); + let predicate = predicate.clone().subst_type_params(self.db, def.into(), &a_ty.parameters); if let Some(obligation) = Obligation::from_predicate(predicate) { self.obligations.push(obligation); } diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index a1466288445..e7283f24cd3 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs @@ -12,7 +12,7 @@ use hir_expand::name::Name; use test_utils::tested_by; use super::{BindingMode, InferenceContext}; -use crate::{db::HirDatabase, utils::variant_data, Substs, Ty, TypeCtor, TypeWalk}; +use crate::{db::HirDatabase, utils::variant_data, Substs, Ty, TypeCtor}; impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn infer_tuple_struct_pat( @@ -34,8 +34,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let expected_ty = var_data .as_ref() .and_then(|d| d.field(&Name::new_tuple_field(i))) - .map_or(Ty::Unknown, |field| field_tys[field].clone()) - .subst(&substs); + .map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs)); let expected_ty = self.normalize_associated_types_in(expected_ty); self.infer_pat(subpat, &expected_ty, default_bm); } @@ -65,7 +64,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for subpat in subpats { let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); let expected_ty = - matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone()).subst(&substs); + matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs)); let expected_ty = self.normalize_associated_types_in(expected_ty); self.infer_pat(subpat.pat, &expected_ty, default_bm); } diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 1f0fd11280a..1e162943cbf 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -45,10 +45,10 @@ use std::{fmt, iter, mem}; use hir_def::{ expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, - HasModule, Lookup, TraitId, TypeAliasId, + HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, generics::TypeParamProvenance, }; -use hir_expand::name::Name; use ra_db::{impl_intern_key, salsa, CrateId}; +use hir_expand::name::Name; use crate::{ db::HirDatabase, @@ -288,14 +288,7 @@ pub enum Ty { Projection(ProjectionTy), /// A type parameter; for example, `T` in `fn f(x: T) {} - Param { - /// The index of the parameter (starting with parameters from the - /// surrounding impl, then the current function). - idx: u32, - /// The name of the parameter, for displaying. - // FIXME get rid of this - name: Name, - }, + Param(TypeParamId), /// A bound type variable. Used during trait resolution to represent Chalk /// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type. @@ -366,15 +359,15 @@ impl Substs { } /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). - pub(crate) fn identity(generic_params: &Generics) -> Substs { + pub(crate) fn type_params(generic_params: &Generics) -> Substs { Substs( - generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone().unwrap_or_else(Name::missing) }).collect(), + generic_params.iter().map(|(id, _)| Ty::Param(id)).collect(), ) } /// Return Substs that replace each parameter by a bound variable. pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { - Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect()) + Substs(generic_params.iter().enumerate().map(|(idx, _)| Ty::Bound(idx as u32)).collect()) } pub fn build_for_def(db: &impl HirDatabase, def: impl Into) -> SubstsBuilder { @@ -422,11 +415,6 @@ impl SubstsBuilder { self.fill((starting_from..).map(Ty::Bound)) } - pub fn fill_with_params(self) -> Self { - let start = self.vec.len() as u32; - self.fill((start..).map(|idx| Ty::Param { idx, name: Name::missing() })) - } - pub fn fill_with_unknown(self) -> Self { self.fill(iter::repeat(Ty::Unknown)) } @@ -762,13 +750,19 @@ pub trait TypeWalk { /// Replaces type parameters in this type using the given `Substs`. (So e.g. /// if `self` is `&[T]`, where type parameter T has index 0, and the /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) - fn subst(self, substs: &Substs) -> Self + // TODO: this should mostly not be used anymore + fn subst_type_params(self, db: &impl HirDatabase, def: GenericDefId, substs: &Substs) -> Self where Self: Sized, { + let generics = generics(db, def); self.fold(&mut |ty| match ty { - Ty::Param { idx, name } => { - substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) + Ty::Param(id) => { + if let Some(idx) = generics.param_idx(id) { + substs.get(idx as usize).cloned().unwrap_or(Ty::Param(id)) + } else { + ty + } } ty => ty, }) @@ -1042,7 +1036,18 @@ impl HirDisplay for Ty { match self { Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, - Ty::Param { name, .. } => write!(f, "{}", name)?, + Ty::Param(id) => { + let generic_params = f.db.generic_params(id.parent); + let param_data = &generic_params.types[id.local_id]; + match param_data.provenance { + TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { + write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? + } + TypeParamProvenance::ArgumentImplTrait => { + write!(f, "impl TODO")? + } + } + }, Ty::Bound(idx) => write!(f, "?{}", idx)?, Ty::Dyn(predicates) | Ty::Opaque(predicates) => { match self { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 88d962b4760..d60b5943342 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -30,7 +30,7 @@ use crate::{ Binders, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, }; -use hir_expand::name::Name; +use hir_def::TypeParamId; #[derive(Debug)] pub struct TyLoweringContext<'a, DB: HirDatabase> { @@ -145,7 +145,16 @@ impl Ty { ImplTraitLoweringMode::Param => { let idx = ctx.impl_trait_counter.get(); ctx.impl_trait_counter.set(idx + 1); - Ty::Param { idx: idx as u32, name: Name::missing() } + if let Some(def) = ctx.resolver.generic_def() { + let generics = generics(ctx.db, def); + let param = generics + .iter() + .nth(idx as usize) + .map_or(Ty::Unknown, |(id, _)| Ty::Param(id)); + param + } else { + Ty::Unknown + } } ImplTraitLoweringMode::Variable => { let idx = ctx.impl_trait_counter.get(); @@ -176,7 +185,7 @@ impl Ty { fn from_hir_only_param( ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef, - ) -> Option { + ) -> Option { let path = match type_ref { TypeRef::Path(path) => path, _ => return None, @@ -192,9 +201,7 @@ impl Ty { _ => return None, }; if let TypeNs::GenericParam(param_id) = resolution { - let generics = generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); - let idx = generics.param_idx(param_id); - Some(idx) + Some(param_id) } else { None } @@ -256,20 +263,18 @@ impl Ty { TypeNs::GenericParam(param_id) => { let generics = generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); - let idx = generics.param_idx(param_id); match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => { - // FIXME: maybe return name in resolution? - let name = generics.param_name(param_id); - Ty::Param { idx, name } + TypeParamLoweringMode::Placeholder => Ty::Param(param_id), + TypeParamLoweringMode::Variable => { + let idx = generics.param_idx(param_id).expect("matching generics"); + Ty::Bound(idx) } - TypeParamLoweringMode::Variable => Ty::Bound(idx), } } TypeNs::SelfType(impl_id) => { let generics = generics(ctx.db, impl_id.into()); let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Substs::identity(&generics), + TypeParamLoweringMode::Placeholder => Substs::type_params(&generics), TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.impl_self_ty(impl_id).subst(&substs) @@ -277,7 +282,7 @@ impl Ty { TypeNs::AdtSelfType(adt) => { let generics = generics(ctx.db, adt.into()); let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Substs::identity(&generics), + TypeParamLoweringMode::Placeholder => Substs::type_params(&generics), TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.ty(adt.into()).subst(&substs) @@ -319,20 +324,28 @@ impl Ty { self_ty: Ty, segment: PathSegment<'_>, ) -> Ty { - let param_idx = match self_ty { - Ty::Param { idx, .. } if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => idx, - Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => idx, - _ => return Ty::Unknown, // Error: Ambiguous associated type - }; let def = match ctx.resolver.generic_def() { Some(def) => def, None => return Ty::Unknown, // this can't actually happen }; - let predicates = ctx.db.generic_predicates_for_param(def.into(), param_idx); + let param_id = match self_ty { + Ty::Param(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, + Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { + let generics = generics(ctx.db, def); + let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { + id + } else { + return Ty::Unknown; + }; + param_id + }, + _ => return Ty::Unknown, // Error: Ambiguous associated type + }; + let predicates = ctx.db.generic_predicates_for_param(param_id); let traits_from_env = predicates.iter().filter_map(|pred| match pred { GenericPredicate::Implemented(tr) => { - if let Ty::Param { idx, .. } = tr.self_ty() { - if *idx == param_idx { + if let Ty::Param(id) = tr.self_ty() { + if *id == param_id { return Some(tr.trait_); } } @@ -530,13 +543,12 @@ impl GenericPredicate { let generic_def = ctx.resolver.generic_def().expect("generics in scope"); let generics = generics(ctx.db, generic_def); let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; - let idx = generics.param_idx(param_id); match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => { - let name = generics.param_name(param_id); - Ty::Param { idx, name } + TypeParamLoweringMode::Placeholder => Ty::Param(param_id), + TypeParamLoweringMode::Variable => { + let idx = generics.param_idx(param_id).expect("matching generics"); + Ty::Bound(idx) } - TypeParamLoweringMode::Variable => Ty::Bound(idx), } } }; @@ -599,17 +611,19 @@ pub fn callable_item_sig(db: &impl HirDatabase, def: CallableDef) -> PolyFnSig { pub(crate) fn field_types_query( db: &impl HirDatabase, variant_id: VariantId, -) -> Arc> { +) -> Arc>> { let var_data = variant_data(db, variant_id); - let resolver = match variant_id { - VariantId::StructId(it) => it.resolver(db), - VariantId::UnionId(it) => it.resolver(db), - VariantId::EnumVariantId(it) => it.parent.resolver(db), + let (resolver, def): (_, GenericDefId) = match variant_id { + VariantId::StructId(it) => (it.resolver(db), it.into()), + VariantId::UnionId(it) => (it.resolver(db), it.into()), + VariantId::EnumVariantId(it) => (it.parent.resolver(db), it.parent.into()), }; + let generics = generics(db, def); let mut res = ArenaMap::default(); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, Ty::from_hir(&ctx, &field_data.type_ref)) + res.insert(field_id, Binders::new(generics.len(), Ty::from_hir(&ctx, &field_data.type_ref))) } Arc::new(res) } @@ -624,23 +638,20 @@ pub(crate) fn field_types_query( /// these are fine: `T: Foo, U: Foo<()>`. pub(crate) fn generic_predicates_for_param_query( db: &impl HirDatabase, - def: GenericDefId, - param_idx: u32, + param_id: TypeParamId, ) -> Arc<[GenericPredicate]> { - let resolver = def.resolver(db); + let resolver = param_id.parent.resolver(db); let ctx = TyLoweringContext::new(db, &resolver); - let generics = generics(db, def); + // let generics = generics(db, def); resolver .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them .filter(|pred| match &pred.target { WherePredicateTarget::TypeRef(type_ref) => { - Ty::from_hir_only_param(&ctx, type_ref) == Some(param_idx) + Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) } WherePredicateTarget::TypeParam(local_id) => { - let param_id = hir_def::TypeParamId { parent: def, local_id: *local_id }; - let idx = generics.param_idx(param_id); - idx == param_idx + *local_id == param_id.local_id } }) .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) @@ -650,8 +661,7 @@ pub(crate) fn generic_predicates_for_param_query( pub(crate) fn generic_predicates_for_param_recover( _db: &impl HirDatabase, _cycle: &[String], - _def: &GenericDefId, - _param_idx: &u32, + _param_id: &TypeParamId, ) -> Arc<[GenericPredicate]> { Arc::new([]) } @@ -905,12 +915,12 @@ pub(crate) fn impl_self_ty_recover( Binders::new(generics.len(), Ty::Unknown) } -pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option { +pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option> { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - let generics = generics(db, impl_id.into()); - let ctx = TyLoweringContext::new(db, &resolver); - let self_ty = db.impl_self_ty(impl_id).subst(&Substs::identity(&generics)); + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Variable); + let self_ty = db.impl_self_ty(impl_id); let target_trait = impl_data.target_trait.as_ref()?; - TraitRef::from_hir(&ctx, target_trait, Some(self_ty.clone())) + Some(Binders::new(self_ty.num_binders, TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value.clone()))?)) } diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index eab2149dc61..5283bff28f3 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -61,7 +61,7 @@ impl CrateImplBlocks { for impl_id in module_data.scope.impls() { match db.impl_trait(impl_id) { Some(tr) => { - res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id); + res.impls_by_trait.entry(tr.value.trait_).or_default().push(impl_id); } None => { let self_ty = db.impl_self_ty(impl_id); diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 446d1281362..1722563aa15 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -697,7 +697,7 @@ fn test>(t: T) { [71; 72) 't': T [77; 96) '{ ...d(); }': () [83; 84) 't': T - [83; 93) 't.method()': [missing name] + [83; 93) 't.method()': U "### ); } diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index dc78e83cd2c..e6f697fa346 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -822,8 +822,7 @@ fn test() { "#, ); // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. - // FIXME: fix type parameter names going missing when going through Chalk - assert_eq!(t, "ApplyL::Out<[missing name]>"); + assert_eq!(t, "ApplyL::Out"); } #[test] diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index fe9cb556cf6..6e97f7dd21f 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -142,8 +142,9 @@ impl ToChalk for Ty { let substitution = proj_ty.parameters.to_chalk(db); chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern() } - Ty::Param { idx, .. } => { - PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize } + Ty::Param(id) => { + let interned_id = db.intern_type_param_id(id); + PlaceholderIndex { ui: UniverseIndex::ROOT, idx: interned_id.as_intern_id().as_usize() } .to_ty::() } Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), @@ -177,7 +178,8 @@ impl ToChalk for Ty { }, chalk_ir::TyData::Placeholder(idx) => { assert_eq!(idx.ui, UniverseIndex::ROOT); - Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } + let interned_id = crate::db::GlobalTypeParamId::from_intern_id(crate::salsa::InternId::from(idx.idx)); + Ty::Param(db.lookup_intern_type_param_id(interned_id)) } chalk_ir::TyData::Alias(proj) => { let associated_ty = from_chalk(db, proj.associated_ty_id); @@ -524,7 +526,7 @@ fn convert_where_clauses( // skip errored predicates completely continue; } - result.push(pred.clone().subst(substs).to_chalk(db)); + result.push(pred.clone().subst_type_params(db, def, substs).to_chalk(db)); } result } @@ -709,12 +711,12 @@ fn impl_block_datum( let trait_ref = db .impl_trait(impl_id) // ImplIds for impls where the trait ref can't be resolved should never reach Chalk - .expect("invalid impl passed to Chalk"); + .expect("invalid impl passed to Chalk") + .value; let impl_data = db.impl_data(impl_id); let generic_params = generics(db, impl_id.into()); let bound_vars = Substs::bound_vars(&generic_params); - let trait_ref = trait_ref.subst(&bound_vars); let trait_ = trait_ref.trait_; let impl_type = if impl_id.lookup(db).container.module(db).krate == krate { chalk_rust_ir::ImplType::Local @@ -789,20 +791,18 @@ fn type_alias_associated_ty_value( _ => panic!("assoc ty value should be in impl"), }; - let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist"); // we don't return any assoc ty values if the impl'd trait can't be resolved + let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved let assoc_ty = db .trait_data(trait_ref.trait_) .associated_type_by_name(&type_alias_data.name) .expect("assoc ty value should not exist"); // validated when building the impl data as well - let generic_params = generics(db, impl_id.into()); - let bound_vars = Substs::bound_vars(&generic_params); - let ty = db.ty(type_alias.into()).subst(&bound_vars); - let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; + let ty = db.ty(type_alias.into()); + let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; let value = chalk_rust_ir::AssociatedTyValue { impl_id: Impl::ImplBlock(impl_id.into()).to_chalk(db), associated_ty_id: assoc_ty.to_chalk(db), - value: make_binders(value_bound, bound_vars.len()), + value: make_binders(value_bound, ty.num_binders), }; Arc::new(value) } diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 77b7de72971..8fa1838bd89 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -99,23 +99,19 @@ pub(crate) struct Generics { } impl Generics { - pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { self.parent_generics .as_ref() .into_iter() - .flat_map(|it| it.params.types.iter()) - .chain(self.params.types.iter()) - .enumerate() - .map(|(i, (_local_id, p))| (i as u32, p)) + .flat_map(|it| it.params.types.iter().map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))) + .chain(self.params.types.iter().map(move |(local_id, p)| (TypeParamId { parent: self.def, local_id }, p))) } - pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator + 'a { + pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator + 'a { self.parent_generics .as_ref() .into_iter() - .flat_map(|it| it.params.types.iter()) - .enumerate() - .map(|(i, (_local_id, p))| (i as u32, p)) + .flat_map(|it| it.params.types.iter().map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))) } pub(crate) fn len(&self) -> usize { @@ -137,16 +133,11 @@ impl Generics { (self_params, list_params, impl_trait_params) } - pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 { - self.find_param(param).0 + pub(crate) fn param_idx(&self, param: TypeParamId) -> Option { + Some(self.find_param(param)?.0) } - pub(crate) fn param_name(&self, param: TypeParamId) -> Name { - // FIXME make this return Option - self.find_param(param).1.name.clone().unwrap_or_else(Name::missing) - } - - fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) { + fn find_param(&self, param: TypeParamId) -> Option<(u32, &TypeParamData)> { if param.parent == self.def { let (idx, (_local_id, data)) = self .params @@ -156,9 +147,10 @@ impl Generics { .find(|(_, (idx, _))| *idx == param.local_id) .unwrap(); let (_total, parent_len, _child) = self.len_split(); - return ((parent_len + idx) as u32, data); + Some(((parent_len + idx) as u32, data)) + } else { + self.parent_generics.as_ref().and_then(|g| g.find_param(param)) } - self.parent_generics.as_ref().unwrap().find_param(param) } } From c6654fd4a70ef149a842e42dc9ef86838148fbe7 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 1 Feb 2020 17:45:43 +0100 Subject: [PATCH 14/25] Fix APIT --- crates/ra_hir_ty/src/lower.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index d60b5943342..42367b1814d 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -31,6 +31,7 @@ use crate::{ TraitEnvironment, TraitRef, Ty, TypeCtor, }; use hir_def::TypeParamId; +use hir_def::generics::TypeParamProvenance; #[derive(Debug)] pub struct TyLoweringContext<'a, DB: HirDatabase> { @@ -149,6 +150,7 @@ impl Ty { let generics = generics(ctx.db, def); let param = generics .iter() + .filter(|(_, data)| data.provenance == TypeParamProvenance::ArgumentImplTrait) .nth(idx as usize) .map_or(Ty::Unknown, |(id, _)| Ty::Param(id)); param From 3397ca679fb0156c9f102ab82354e2bcef5f4dd1 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 2 Feb 2020 13:04:22 +0100 Subject: [PATCH 15/25] Fix APIT some more --- crates/ra_hir_ty/src/infer.rs | 7 +- crates/ra_hir_ty/src/lib.rs | 153 ++++++++++++++------------- crates/ra_hir_ty/src/lower.rs | 5 +- crates/ra_hir_ty/src/tests/traits.rs | 51 +++++---- 4 files changed, 115 insertions(+), 101 deletions(-) diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 0d65984eefb..8d5b7c94328 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -479,8 +479,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn collect_fn(&mut self, data: &FunctionData) { let body = Arc::clone(&self.body); // avoid borrow checker problem - for (type_ref, pat) in data.params.iter().zip(body.params.iter()) { - let ty = self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Param); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver).with_impl_trait_mode(ImplTraitLoweringMode::Param); + let param_tys = data.params.iter().map(|type_ref| Ty::from_hir(&ctx, type_ref)).collect::>(); + for (ty, pat) in param_tys.into_iter().zip(body.params.iter()) { + let ty = self.insert_type_vars(ty); + let ty = self.normalize_associated_types_in(ty); self.infer_pat(*pat, &ty, BindingMode::default()); } diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 1e162943cbf..6eccd7fa843 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -44,11 +44,11 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use hir_def::{ - expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, - HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, generics::TypeParamProvenance, + expr::ExprId, generics::TypeParamProvenance, type_ref::Mutability, AdtId, AssocContainerId, + DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, }; -use ra_db::{impl_intern_key, salsa, CrateId}; use hir_expand::name::Name; +use ra_db::{impl_intern_key, salsa, CrateId}; use crate::{ db::HirDatabase, @@ -360,9 +360,7 @@ impl Substs { /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). pub(crate) fn type_params(generic_params: &Generics) -> Substs { - Substs( - generic_params.iter().map(|(id, _)| Ty::Param(id)).collect(), - ) + Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect()) } /// Return Substs that replace each parameter by a bound variable. @@ -448,7 +446,9 @@ pub struct Binders { } impl Binders { - pub fn new(num_binders: usize, value: T) -> Self { Self { num_binders, value } } + pub fn new(num_binders: usize, value: T) -> Self { + Self { num_binders, value } + } } impl Binders { @@ -906,8 +906,7 @@ impl HirDisplay for ApplicationTy { write!(f, ") -> {}", sig.ret().display(f.db))?; } TypeCtor::FnDef(def) => { - let sig = f.db.callable_item_signature(def) - .subst(&self.parameters); + let sig = f.db.callable_item_signature(def).subst(&self.parameters); let name = match def { CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), @@ -1037,17 +1036,19 @@ impl HirDisplay for Ty { Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, Ty::Param(id) => { - let generic_params = f.db.generic_params(id.parent); - let param_data = &generic_params.types[id.local_id]; + let generics = generics(f.db, id.parent); + let param_data = &generics.params.types[id.local_id]; match param_data.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? } TypeParamProvenance::ArgumentImplTrait => { - write!(f, "impl TODO")? + let bounds = f.db.generic_predicates_for_param(*id); + write!(f, "impl ")?; + write_bounds_like_dyn_trait(&bounds, f)?; } } - }, + } Ty::Bound(idx) => write!(f, "?{}", idx)?, Ty::Dyn(predicates) | Ty::Opaque(predicates) => { match self { @@ -1055,66 +1056,7 @@ impl HirDisplay for Ty { Ty::Opaque(_) => write!(f, "impl ")?, _ => unreachable!(), }; - // Note: This code is written to produce nice results (i.e. - // corresponding to surface Rust) for types that can occur in - // actual Rust. It will have weird results if the predicates - // aren't as expected (i.e. self types = $0, projection - // predicates for a certain trait come after the Implemented - // predicate for that trait). - let mut first = true; - let mut angle_open = false; - for p in predicates.iter() { - match p { - GenericPredicate::Implemented(trait_ref) => { - if angle_open { - write!(f, ">")?; - } - if !first { - write!(f, " + ")?; - } - // We assume that the self type is $0 (i.e. the - // existential) here, which is the only thing that's - // possible in actual Rust, and hence don't print it - write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; - if trait_ref.substs.len() > 1 { - write!(f, "<")?; - f.write_joined(&trait_ref.substs[1..], ", ")?; - // there might be assoc type bindings, so we leave the angle brackets open - angle_open = true; - } - } - GenericPredicate::Projection(projection_pred) => { - // in types in actual Rust, these will always come - // after the corresponding Implemented predicate - if angle_open { - write!(f, ", ")?; - } else { - write!(f, "<")?; - angle_open = true; - } - let name = - f.db.type_alias_data(projection_pred.projection_ty.associated_ty) - .name - .clone(); - write!(f, "{} = ", name)?; - projection_pred.ty.hir_fmt(f)?; - } - GenericPredicate::Error => { - if angle_open { - // impl Trait - write!(f, ", ")?; - } else if !first { - // impl Trait + {error} - write!(f, " + ")?; - } - p.hir_fmt(f)?; - } - } - first = false; - } - if angle_open { - write!(f, ">")?; - } + write_bounds_like_dyn_trait(&predicates, f)?; } Ty::Unknown => write!(f, "{{unknown}}")?, Ty::Infer(..) => write!(f, "_")?, @@ -1123,6 +1065,71 @@ impl HirDisplay for Ty { } } +fn write_bounds_like_dyn_trait( + predicates: &[GenericPredicate], + f: &mut HirFormatter, +) -> fmt::Result { + // Note: This code is written to produce nice results (i.e. + // corresponding to surface Rust) for types that can occur in + // actual Rust. It will have weird results if the predicates + // aren't as expected (i.e. self types = $0, projection + // predicates for a certain trait come after the Implemented + // predicate for that trait). + let mut first = true; + let mut angle_open = false; + for p in predicates.iter() { + match p { + GenericPredicate::Implemented(trait_ref) => { + if angle_open { + write!(f, ">")?; + } + if !first { + write!(f, " + ")?; + } + // We assume that the self type is $0 (i.e. the + // existential) here, which is the only thing that's + // possible in actual Rust, and hence don't print it + write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; + if trait_ref.substs.len() > 1 { + write!(f, "<")?; + f.write_joined(&trait_ref.substs[1..], ", ")?; + // there might be assoc type bindings, so we leave the angle brackets open + angle_open = true; + } + } + GenericPredicate::Projection(projection_pred) => { + // in types in actual Rust, these will always come + // after the corresponding Implemented predicate + if angle_open { + write!(f, ", ")?; + } else { + write!(f, "<")?; + angle_open = true; + } + let name = + f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); + write!(f, "{} = ", name)?; + projection_pred.ty.hir_fmt(f)?; + } + GenericPredicate::Error => { + if angle_open { + // impl Trait + write!(f, ", ")?; + } else if !first { + // impl Trait + {error} + write!(f, " + ")?; + } + p.hir_fmt(f)?; + } + } + first = false; + } + if angle_open { + write!(f, ">")?; + } + Ok(()) +} + impl TraitRef { fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { if f.should_truncate() { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 42367b1814d..e375c48470b 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -10,12 +10,13 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, - generics::{WherePredicate, WherePredicateTarget}, + generics::{WherePredicate, WherePredicateTarget, TypeParamProvenance}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, + TypeParamId }; use ra_arena::map::ArenaMap; use ra_db::CrateId; @@ -30,8 +31,6 @@ use crate::{ Binders, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, }; -use hir_def::TypeParamId; -use hir_def::generics::TypeParamProvenance; #[derive(Debug)] pub struct TyLoweringContext<'a, DB: HirDatabase> { diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e6f697fa346..bae5eae0742 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -856,11 +856,11 @@ trait Trait { fn foo(&self) -> T; fn foo2(&self) -> i64; } -fn bar(impl Trait) {} +fn bar(x: impl Trait) {} struct S(T); impl Trait for S {} -fn test(x: impl Trait, y: &impl Trait) { +fn test(x: impl Trait, y: &impl Trait) { x; y; let z = S(1); @@ -876,27 +876,32 @@ fn test(x: impl Trait, y: &impl Trait) { @r###" [30; 34) 'self': &Self [55; 59) 'self': &Self - [99; 101) '{}': () - [111; 112) 'x': impl Trait - [131; 132) 'y': &impl Trait - [152; 269) '{ ...2(); }': () - [158; 159) 'x': impl Trait - [165; 166) 'y': &impl Trait - [176; 177) 'z': impl Trait - [180; 183) 'bar': fn bar() -> impl Trait - [180; 185) 'bar()': impl Trait - [191; 192) 'x': impl Trait - [191; 198) 'x.foo()': u64 - [204; 205) 'y': &impl Trait - [204; 211) 'y.foo()': u64 - [217; 218) 'z': impl Trait - [217; 224) 'z.foo()': u64 - [230; 231) 'x': impl Trait - [230; 238) 'x.foo2()': i64 - [244; 245) 'y': &impl Trait - [244; 252) 'y.foo2()': i64 - [258; 259) 'z': impl Trait - [258; 266) 'z.foo2()': i64 + [78; 79) 'x': impl Trait + [98; 100) '{}': () + [155; 156) 'x': impl Trait + [175; 176) 'y': &impl Trait + [196; 324) '{ ...2(); }': () + [202; 203) 'x': impl Trait + [209; 210) 'y': &impl Trait + [220; 221) 'z': S + [224; 225) 'S': S(u16) -> S + [224; 228) 'S(1)': S + [226; 227) '1': u16 + [234; 237) 'bar': fn bar>(S) -> () + [234; 240) 'bar(z)': () + [238; 239) 'z': S + [246; 247) 'x': impl Trait + [246; 253) 'x.foo()': u64 + [259; 260) 'y': &impl Trait + [259; 266) 'y.foo()': u32 + [272; 273) 'z': S + [272; 279) 'z.foo()': u16 + [285; 286) 'x': impl Trait + [285; 293) 'x.foo2()': i64 + [299; 300) 'y': &impl Trait + [299; 307) 'y.foo2()': i64 + [313; 314) 'z': S + [313; 321) 'z.foo2()': i64 "### ); } From 86348f5994cdc3831edf3a5582d6d9d576fd1d80 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 2 Feb 2020 13:43:04 +0100 Subject: [PATCH 16/25] Comment fixes / todos --- crates/ra_hir_ty/src/infer/expr.rs | 1 + crates/ra_hir_ty/src/lib.rs | 2 ++ crates/ra_hir_ty/src/lower.rs | 11 +++++------ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 8b83784993d..b32df8e90ef 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -587,6 +587,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.write_method_resolution(tgt_expr, func); (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into()))) } + // TODO fix this None => (receiver_ty, Binders::new(0, Ty::Unknown), None), }; let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 6eccd7fa843..1da4bcc19bf 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -288,10 +288,12 @@ pub enum Ty { Projection(ProjectionTy), /// A type parameter; for example, `T` in `fn f(x: T) {} + // TODO fix documentation Param(TypeParamId), /// A bound type variable. Used during trait resolution to represent Chalk /// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type. + // TODO fix documentation Bound(u32), /// A type variable used during type checking. Not to be confused with a diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index e375c48470b..76e2fbabf8a 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -37,10 +37,9 @@ pub struct TyLoweringContext<'a, DB: HirDatabase> { pub db: &'a DB, pub resolver: &'a Resolver, /// Note: Conceptually, it's thinkable that we could be in a location where - /// some type params are quantified universally (and should be represented - /// as placeholders), and others are quantified existentially (and should be - /// converted to variables). I think in practice, this isn't possible - /// currently, so this should be fine for now. + /// some type params should be represented as placeholders, and others + /// should be converted to variables. I think in practice, this isn't + /// possible currently, so this should be fine for now. pub type_param_mode: TypeParamLoweringMode, pub impl_trait_mode: ImplTraitLoweringMode, pub impl_trait_counter: std::cell::Cell, @@ -71,8 +70,8 @@ pub enum ImplTraitLoweringMode { /// types of functions we're calling. Opaque, /// `impl Trait` gets lowered into a type variable. Used for argument - /// position impl Trait currently, since it allows us to support that - /// without Chalk. + /// position impl Trait when inside the respective function, since it allows + /// us to support that without Chalk. Param, /// `impl Trait` gets lowered into a variable that can unify with some /// type. This is used in places where values flow 'in', i.e. for arguments From a3d8cffde39bfb0d50b87a8ded5e0534adec4cd5 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 2 Feb 2020 17:11:54 +0100 Subject: [PATCH 17/25] Use variables in predicates as well --- crates/ra_hir_ty/src/db.rs | 4 +- crates/ra_hir_ty/src/infer/expr.rs | 4 +- crates/ra_hir_ty/src/lib.rs | 28 ++--------- crates/ra_hir_ty/src/lower.rs | 73 ++++++++++++++++------------ crates/ra_hir_ty/src/traits/chalk.rs | 6 +-- 5 files changed, 52 insertions(+), 63 deletions(-) diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 7684ade0681..21ab22fa981 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -50,10 +50,10 @@ pub trait HirDatabase: DefDatabase { fn generic_predicates_for_param( &self, param_id: TypeParamId, - ) -> Arc<[GenericPredicate]>; + ) -> Arc<[Binders]>; #[salsa::invoke(crate::lower::generic_predicates_query)] - fn generic_predicates(&self, def: GenericDefId) -> Arc<[GenericPredicate]>; + fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders]>; #[salsa::invoke(crate::lower::generic_defaults_query)] fn generic_defaults(&self, def: GenericDefId) -> Substs; diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index b32df8e90ef..b69785e55a5 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -20,7 +20,7 @@ use crate::{ traits::InEnvironment, utils::{generics, variant_data, Generics}, ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty, - TypeCtor, TypeWalk, Uncertain, Binders, + TypeCtor, Uncertain, Binders, }; use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; @@ -686,7 +686,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if let TypeCtor::FnDef(def) = a_ty.ctor { let generic_predicates = self.db.generic_predicates(def.into()); for predicate in generic_predicates.iter() { - let predicate = predicate.clone().subst_type_params(self.db, def.into(), &a_ty.parameters); + let predicate = predicate.clone().subst(&a_ty.parameters); if let Some(obligation) = Obligation::from_predicate(predicate) { self.obligations.push(obligation); } diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 1da4bcc19bf..a685e70c2ee 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -749,28 +749,7 @@ pub trait TypeWalk { self } - /// Replaces type parameters in this type using the given `Substs`. (So e.g. - /// if `self` is `&[T]`, where type parameter T has index 0, and the - /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) - // TODO: this should mostly not be used anymore - fn subst_type_params(self, db: &impl HirDatabase, def: GenericDefId, substs: &Substs) -> Self - where - Self: Sized, - { - let generics = generics(db, def); - self.fold(&mut |ty| match ty { - Ty::Param(id) => { - if let Some(idx) = generics.param_idx(id) { - substs.get(idx as usize).cloned().unwrap_or(Ty::Param(id)) - } else { - ty - } - } - ty => ty, - }) - } - - /// Substitutes `Ty::Bound` vars (as opposed to type parameters). + /// Substitutes `Ty::Bound` vars with the given substitution. fn subst_bound_vars(mut self, substs: &Substs) -> Self where Self: Sized, @@ -1045,9 +1024,10 @@ impl HirDisplay for Ty { write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? } TypeParamProvenance::ArgumentImplTrait => { - let bounds = f.db.generic_predicates_for_param(*id); write!(f, "impl ")?; - write_bounds_like_dyn_trait(&bounds, f)?; + let bounds = f.db.generic_predicates_for_param(*id); + let substs = Substs::type_params(&generics); + write_bounds_like_dyn_trait(&bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), f)?; } } } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 76e2fbabf8a..8471117489e 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -10,13 +10,13 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, - generics::{WherePredicate, WherePredicateTarget, TypeParamProvenance}, + generics::{TypeParamProvenance, WherePredicate, WherePredicateTarget}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, - LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, - TypeParamId + LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, + VariantId, }; use ra_arena::map::ArenaMap; use ra_db::CrateId; @@ -148,7 +148,9 @@ impl Ty { let generics = generics(ctx.db, def); let param = generics .iter() - .filter(|(_, data)| data.provenance == TypeParamProvenance::ArgumentImplTrait) + .filter(|(_, data)| { + data.provenance == TypeParamProvenance::ArgumentImplTrait + }) .nth(idx as usize) .map_or(Ty::Unknown, |(id, _)| Ty::Param(id)); param @@ -338,19 +340,12 @@ impl Ty { return Ty::Unknown; }; param_id - }, + } _ => return Ty::Unknown, // Error: Ambiguous associated type }; let predicates = ctx.db.generic_predicates_for_param(param_id); - let traits_from_env = predicates.iter().filter_map(|pred| match pred { - GenericPredicate::Implemented(tr) => { - if let Ty::Param(id) = tr.self_ty() { - if *id == param_id { - return Some(tr.trait_); - } - } - None - } + let traits_from_env = predicates.iter().filter_map(|pred| match &pred.value { + GenericPredicate::Implemented(tr) => Some(tr.trait_), _ => None, }); let traits = traits_from_env.flat_map(|t| all_super_traits(ctx.db, t)); @@ -620,8 +615,8 @@ pub(crate) fn field_types_query( }; let generics = generics(db, def); let mut res = ArenaMap::default(); - let ctx = TyLoweringContext::new(db, &resolver) - .with_type_param_mode(TypeParamLoweringMode::Variable); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, Binders::new(generics.len(), Ty::from_hir(&ctx, &field_data.type_ref))) } @@ -639,10 +634,11 @@ pub(crate) fn field_types_query( pub(crate) fn generic_predicates_for_param_query( db: &impl HirDatabase, param_id: TypeParamId, -) -> Arc<[GenericPredicate]> { +) -> Arc<[Binders]> { let resolver = param_id.parent.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver); - // let generics = generics(db, def); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); + let generics = generics(db, param_id.parent); resolver .where_predicates_in_scope() // we have to filter out all other predicates *first*, before attempting to lower them @@ -650,11 +646,12 @@ pub(crate) fn generic_predicates_for_param_query( WherePredicateTarget::TypeRef(type_ref) => { Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) } - WherePredicateTarget::TypeParam(local_id) => { - *local_id == param_id.local_id - } + WherePredicateTarget::TypeParam(local_id) => *local_id == param_id.local_id, + }) + .flat_map(|pred| { + GenericPredicate::from_where_predicate(&ctx, pred) + .map(|p| Binders::new(generics.len(), p)) }) - .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect() } @@ -662,13 +659,14 @@ pub(crate) fn generic_predicates_for_param_recover( _db: &impl HirDatabase, _cycle: &[String], _param_id: &TypeParamId, -) -> Arc<[GenericPredicate]> { +) -> Arc<[Binders]> { Arc::new([]) } impl TraitEnvironment { pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver) + .with_type_param_mode(TypeParamLoweringMode::Placeholder); let predicates = resolver .where_predicates_in_scope() .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) @@ -682,12 +680,17 @@ impl TraitEnvironment { pub(crate) fn generic_predicates_query( db: &impl HirDatabase, def: GenericDefId, -) -> Arc<[GenericPredicate]> { +) -> Arc<[Binders]> { let resolver = def.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); + let generics = generics(db, def); resolver .where_predicates_in_scope() - .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) + .flat_map(|pred| { + GenericPredicate::from_where_predicate(&ctx, pred) + .map(|p| Binders::new(generics.len(), p)) + }) .collect() } @@ -915,12 +918,18 @@ pub(crate) fn impl_self_ty_recover( Binders::new(generics.len(), Ty::Unknown) } -pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option> { +pub(crate) fn impl_trait_query( + db: &impl HirDatabase, + impl_id: ImplId, +) -> Option> { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db); - let ctx = TyLoweringContext::new(db, &resolver) - .with_type_param_mode(TypeParamLoweringMode::Variable); + let ctx = + TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); let self_ty = db.impl_self_ty(impl_id); let target_trait = impl_data.target_trait.as_ref()?; - Some(Binders::new(self_ty.num_binders, TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value.clone()))?)) + Some(Binders::new( + self_ty.num_binders, + TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value.clone()))?, + )) } diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 6e97f7dd21f..8260bd15730 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -14,7 +14,7 @@ use ra_db::{ use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; use crate::{ db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, - ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, + ProjectionTy, Substs, TraitRef, Ty, TypeCtor, }; #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] @@ -522,11 +522,11 @@ fn convert_where_clauses( let generic_predicates = db.generic_predicates(def); let mut result = Vec::with_capacity(generic_predicates.len()); for pred in generic_predicates.iter() { - if pred.is_error() { + if pred.value.is_error() { // skip errored predicates completely continue; } - result.push(pred.clone().subst_type_params(db, def, substs).to_chalk(db)); + result.push(pred.clone().subst(substs).to_chalk(db)); } result } From 0718682cffaae34e5c106c793c60f6706fc04b05 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 4 Feb 2020 21:33:03 +0100 Subject: [PATCH 18/25] Fix compilation of other crates --- crates/ra_hir/src/code_model.rs | 25 +++++++++++++++---------- crates/ra_hir_ty/src/lib.rs | 10 ++++++++-- crates/ra_hir_ty/src/lower.rs | 4 ++-- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 817c27410a1..63c85ca34a8 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -13,6 +13,7 @@ use hir_def::{ AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, + GenericDefId }; use hir_expand::{ diagnostics::DiagnosticSink, @@ -21,7 +22,8 @@ use hir_expand::{ }; use hir_ty::{ autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy, - Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk, + Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, + Substs }; use ra_db::{CrateId, Edition, FileId}; use ra_prof::profile; @@ -270,7 +272,13 @@ impl StructField { pub fn ty(&self, db: &impl HirDatabase) -> Type { let var_id = self.parent.into(); - let ty = db.field_types(var_id)[self.id].clone(); + let generic_def_id: GenericDefId = match self.parent { + VariantDef::Struct(it) => it.id.into(), + VariantDef::Union(it) => it.id.into(), + VariantDef::EnumVariant(it) => it.parent.id.into(), + }; + let substs = Substs::type_params(db, generic_def_id); + let ty = db.field_types(var_id)[self.id].clone().subst(&substs); Type::new(db, self.parent.module(db).id.krate.into(), var_id, ty) } @@ -789,11 +797,7 @@ impl ImplBlock { pub fn target_ty(&self, db: &impl HirDatabase) -> Type { let impl_data = db.impl_data(self.id); let resolver = self.id.resolver(db); - let ctx = hir_ty::TyLoweringContext { - db, - resolver: &resolver, - impl_trait_mode: hir_ty::ImplTraitLoweringMode::Disallowed, - }; + let ctx = hir_ty::TyLoweringContext::new(db, &resolver); let environment = TraitEnvironment::lower(db, &resolver); let ty = Ty::from_hir(&ctx, &impl_data.target_type); Type { @@ -856,9 +860,10 @@ impl Type { fn from_def( db: &impl HirDatabase, krate: CrateId, - def: impl HasResolver + Into, + def: impl HasResolver + Into + Into, ) -> Type { - let ty = db.ty(def.into()); + let substs = Substs::type_params(db, def); + let ty = db.ty(def.into()).subst(&substs); Type::new(db, krate, def, ty) } @@ -955,7 +960,7 @@ impl Type { match a_ty.ctor { TypeCtor::Tuple { .. } => { for ty in a_ty.parameters.iter() { - let ty = ty.clone().subst(&a_ty.parameters); + let ty = ty.clone(); res.push(self.derived(ty)); } } diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index a685e70c2ee..314be17b87f 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -361,10 +361,16 @@ impl Substs { } /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). - pub(crate) fn type_params(generic_params: &Generics) -> Substs { + pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs { Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect()) } + /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). + pub fn type_params(db: &impl HirDatabase, def: impl Into) -> Substs { + let params = generics(db, def.into()); + Substs::type_params_for_generics(¶ms) + } + /// Return Substs that replace each parameter by a bound variable. pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { Substs(generic_params.iter().enumerate().map(|(idx, _)| Ty::Bound(idx as u32)).collect()) @@ -1026,7 +1032,7 @@ impl HirDisplay for Ty { TypeParamProvenance::ArgumentImplTrait => { write!(f, "impl ")?; let bounds = f.db.generic_predicates_for_param(*id); - let substs = Substs::type_params(&generics); + let substs = Substs::type_params_for_generics(&generics); write_bounds_like_dyn_trait(&bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), f)?; } } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 8471117489e..0d4c075af48 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -276,7 +276,7 @@ impl Ty { TypeNs::SelfType(impl_id) => { let generics = generics(ctx.db, impl_id.into()); let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Substs::type_params(&generics), + TypeParamLoweringMode::Placeholder => Substs::type_params_for_generics(&generics), TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.impl_self_ty(impl_id).subst(&substs) @@ -284,7 +284,7 @@ impl Ty { TypeNs::AdtSelfType(adt) => { let generics = generics(ctx.db, adt.into()); let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Substs::type_params(&generics), + TypeParamLoweringMode::Placeholder => Substs::type_params_for_generics(&generics), TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.ty(adt.into()).subst(&substs) From 6787f124b5557120cd1e4557cbdb59aa7f215be6 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 15:13:00 +0100 Subject: [PATCH 19/25] Clean up RPIT a bit --- crates/ra_assists/src/handlers/add_new.rs | 1 + crates/ra_hir_ty/src/infer.rs | 28 ++--------------------- crates/ra_hir_ty/src/infer/expr.rs | 1 - crates/ra_hir_ty/src/marks.rs | 1 - crates/ra_hir_ty/src/tests/traits.rs | 24 +++++++++---------- 5 files changed, 14 insertions(+), 41 deletions(-) diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index a08639311f4..12d63b54da0 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs @@ -144,6 +144,7 @@ fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option InferenceContext<'a, D> { self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed) } - /// Replaces `impl Trait` in `ty` by type variables and obligations for - /// those variables. This is done for function arguments when calling a - /// function, and for return types when inside the function body, i.e. in - /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl - /// Trait` is represented by `Ty::Opaque`. - fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty { - ty.fold(&mut |ty| match ty { - Ty::Opaque(preds) => { - tested_by!(insert_vars_for_impl_trait); - let var = self.table.new_type_var(); - let var_subst = Substs::builder(1).push(var.clone()).build(); - self.obligations.extend( - preds - .iter() - .map(|pred| pred.clone().subst_bound_vars(&var_subst)) - .filter_map(Obligation::from_predicate), - ); - var - } - _ => ty, - }) - } - /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty { @@ -487,8 +463,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.infer_pat(*pat, &ty, BindingMode::default()); } - let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Variable); - self.return_ty = self.insert_vars_for_impl_trait(return_ty); + let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT + self.return_ty = return_ty; } fn infer_body(&mut self) { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index b69785e55a5..6222bd90e6e 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -635,7 +635,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { continue; } - let param_ty = self.insert_vars_for_impl_trait(param_ty); let param_ty = self.normalize_associated_types_in(param_ty); self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); } diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index fe74acf119b..0f754eb9c75 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs @@ -6,5 +6,4 @@ test_utils::marks!( type_var_resolves_to_int_var match_ergonomics_ref coerce_merge_fail_fallback - insert_vars_for_impl_trait ); diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index bae5eae0742..134cea8d86c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1,7 +1,6 @@ use insta::assert_snapshot; use ra_db::fixture::WithFixture; -use test_utils::covers; use super::{infer, infer_with_mismatches, type_at, type_at_pos}; use crate::test_db::TestDB; @@ -1650,7 +1649,6 @@ fn test() where T: Trait, U: Trait { #[test] fn unify_impl_trait() { - covers!(insert_vars_for_impl_trait); assert_snapshot!( infer_with_mismatches(r#" trait Trait {} @@ -1682,26 +1680,26 @@ fn test() -> impl Trait { [172; 183) '{ loop {} }': T [174; 181) 'loop {}': ! [179; 181) '{}': () - [214; 310) '{ ...t()) }': S + [214; 310) '{ ...t()) }': S<{unknown}> [224; 226) 's1': S - [229; 230) 'S': S(T) -> S + [229; 230) 'S': S(u32) -> S [229; 241) 'S(default())': S - [231; 238) 'default': fn default() -> T + [231; 238) 'default': fn default() -> u32 [231; 240) 'default()': u32 - [247; 250) 'foo': fn foo(impl Trait) -> () + [247; 250) 'foo': fn foo>(S) -> () [247; 254) 'foo(s1)': () [251; 253) 's1': S [264; 265) 'x': i32 - [273; 276) 'bar': fn bar(impl Trait) -> T + [273; 276) 'bar': fn bar>(S) -> i32 [273; 290) 'bar(S(...lt()))': i32 - [277; 278) 'S': S(T) -> S + [277; 278) 'S': S(i32) -> S [277; 289) 'S(default())': S - [279; 286) 'default': fn default() -> T + [279; 286) 'default': fn default() -> i32 [279; 288) 'default()': i32 - [296; 297) 'S': S(T) -> S - [296; 308) 'S(default())': S - [298; 305) 'default': fn default() -> T - [298; 307) 'default()': i32 + [296; 297) 'S': S<{unknown}>({unknown}) -> S<{unknown}> + [296; 308) 'S(default())': S<{unknown}> + [298; 305) 'default': fn default<{unknown}>() -> {unknown} + [298; 307) 'default()': {unknown} "### ); } From dded90a748737c3661aad043524f2248e324c867 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 15:13:15 +0100 Subject: [PATCH 20/25] Formatting --- crates/ra_hir/src/code_model.rs | 10 ++--- crates/ra_hir_def/src/generics.rs | 17 +++++--- crates/ra_hir_def/src/type_ref.rs | 4 +- crates/ra_hir_ty/src/db.rs | 7 ++-- crates/ra_hir_ty/src/infer.rs | 9 ++-- crates/ra_hir_ty/src/infer/coerce.rs | 8 +--- crates/ra_hir_ty/src/infer/expr.rs | 4 +- crates/ra_hir_ty/src/infer/path.rs | 5 +-- crates/ra_hir_ty/src/lib.rs | 5 ++- crates/ra_hir_ty/src/lower.rs | 8 +++- crates/ra_hir_ty/src/traits/chalk.rs | 11 +++-- crates/ra_hir_ty/src/utils.rs | 63 +++++++++++++++++++++------- 12 files changed, 98 insertions(+), 53 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 63c85ca34a8..4d964172854 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -10,10 +10,9 @@ use hir_def::{ per_ns::PerNs, resolver::HasResolver, type_ref::{Mutability, TypeRef}, - AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId, - LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, - TypeParamId, UnionId, - GenericDefId + AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, + LocalEnumVariantId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, + TraitId, TypeAliasId, TypeParamId, UnionId, }; use hir_expand::{ diagnostics::DiagnosticSink, @@ -22,8 +21,7 @@ use hir_expand::{ }; use hir_ty::{ autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy, - Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, - Substs + Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, }; use ra_db::{CrateId, Edition, FileId}; use ra_prof::profile; diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index e4e616519ba..f765e6edc20 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -61,7 +61,7 @@ pub struct WherePredicate { pub enum WherePredicateTarget { TypeRef(TypeRef), /// For desugared where predicates that can directly refer to a type param. - TypeParam(LocalTypeParamId) + TypeParam(LocalTypeParamId), } type SourceMap = ArenaMap>; @@ -197,7 +197,8 @@ impl GenericParams { return; } let bound = TypeBound::from_ast(bound); - self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); + self.where_predicates + .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); } fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { @@ -212,7 +213,7 @@ impl GenericParams { for bound in bounds { self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeParam(param_id), - bound: bound.clone() + bound: bound.clone(), }); } } @@ -226,9 +227,13 @@ impl GenericParams { } pub fn find_trait_self_param(&self) -> Option { - self.types - .iter() - .find_map(|(id, p)| if p.provenance == TypeParamProvenance::TraitSelf { Some(id) } else { None }) + self.types.iter().find_map(|(id, p)| { + if p.provenance == TypeParamProvenance::TraitSelf { + Some(id) + } else { + None + } + }) } } diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index 10941477053..102fdb13d72 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs @@ -131,9 +131,7 @@ impl TypeRef { fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { f(type_ref); match type_ref { - TypeRef::Fn(types) | TypeRef::Tuple(types) => { - types.iter().for_each(|t| go(t, f)) - } + TypeRef::Fn(types) | TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)), TypeRef::RawPtr(type_ref, _) | TypeRef::Reference(type_ref, _) | TypeRef::Array(type_ref) diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 21ab22fa981..e9bfcfa1768 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs @@ -3,7 +3,8 @@ use std::sync::Arc; use hir_def::{ - db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalStructFieldId, TraitId, VariantId, TypeParamId, + db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalStructFieldId, TraitId, TypeParamId, + VariantId, }; use ra_arena::map::ArenaMap; use ra_db::{impl_intern_key, salsa, CrateId}; @@ -12,8 +13,8 @@ use ra_prof::profile; use crate::{ method_resolution::CrateImplBlocks, traits::{chalk, AssocTyValue, Impl}, - CallableDef, PolyFnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor, - ValueTyDefId, Binders, + Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, + TyDefId, TypeCtor, ValueTyDefId, }; #[salsa::query_group(HirDatabaseStorage)] diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index dec6bd84c2e..a9d958c8bcd 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -278,7 +278,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { impl_trait_mode: ImplTraitLoweringMode, ) -> Ty { // FIXME use right resolver for block - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver).with_impl_trait_mode(impl_trait_mode); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + .with_impl_trait_mode(impl_trait_mode); let ty = Ty::from_hir(&ctx, type_ref); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) @@ -455,8 +456,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn collect_fn(&mut self, data: &FunctionData) { let body = Arc::clone(&self.body); // avoid borrow checker problem - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver).with_impl_trait_mode(ImplTraitLoweringMode::Param); - let param_tys = data.params.iter().map(|type_ref| Ty::from_hir(&ctx, type_ref)).collect::>(); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + .with_impl_trait_mode(ImplTraitLoweringMode::Param); + let param_tys = + data.params.iter().map(|type_ref| Ty::from_hir(&ctx, type_ref)).collect::>(); for (ty, pat) in param_tys.into_iter().zip(body.params.iter()) { let ty = self.insert_type_vars(ty); let ty = self.normalize_associated_types_in(ty); diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 2a95678984e..f68a1439f8f 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs @@ -66,9 +66,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // This works for smart-pointer-like coercion, which covers all impls from std. st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| { match (ty1, ty2) { - (Ty::Bound(idx1), Ty::Bound(idx2)) - if idx1 != idx2 => - { + (Ty::Bound(idx1), Ty::Bound(idx2)) if idx1 != idx2 => { Some(((*ctor1, *ctor2), i)) } _ => None, @@ -277,9 +275,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let mut multiple_used = false; fields.for_each(|(field_id, _data)| { field_tys[field_id].value.walk(&mut |ty| match ty { - &Ty::Bound(idx) if idx == unsize_generic_index => { - multiple_used = true - } + &Ty::Bound(idx) if idx == unsize_generic_index => multiple_used = true, _ => {} }) }); diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 6222bd90e6e..8c360bcadcf 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -19,8 +19,8 @@ use crate::{ method_resolution, op, traits::InEnvironment, utils::{generics, variant_data, Generics}, - ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty, - TypeCtor, Uncertain, Binders, + ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, + Ty, TypeCtor, Uncertain, }; use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index fcf13b0b313..686ce7a218b 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -9,10 +9,7 @@ use hir_def::{ }; use hir_expand::name::Name; -use crate::{ - db::HirDatabase, method_resolution, Substs, Ty, - ValueTyDefId -}; +use crate::{db::HirDatabase, method_resolution, Substs, Ty, ValueTyDefId}; use super::{ExprOrPatId, InferenceContext, TraitRef}; diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 314be17b87f..60c7fd0e5d9 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -1033,7 +1033,10 @@ impl HirDisplay for Ty { write!(f, "impl ")?; let bounds = f.db.generic_predicates_for_param(*id); let substs = Substs::type_params_for_generics(&generics); - write_bounds_like_dyn_trait(&bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), f)?; + write_bounds_like_dyn_trait( + &bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), + f, + )?; } } } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 0d4c075af48..4168e750961 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -276,7 +276,9 @@ impl Ty { TypeNs::SelfType(impl_id) => { let generics = generics(ctx.db, impl_id.into()); let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Substs::type_params_for_generics(&generics), + TypeParamLoweringMode::Placeholder => { + Substs::type_params_for_generics(&generics) + } TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.impl_self_ty(impl_id).subst(&substs) @@ -284,7 +286,9 @@ impl Ty { TypeNs::AdtSelfType(adt) => { let generics = generics(ctx.db, adt.into()); let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Substs::type_params_for_generics(&generics), + TypeParamLoweringMode::Placeholder => { + Substs::type_params_for_generics(&generics) + } TypeParamLoweringMode::Variable => Substs::bound_vars(&generics), }; ctx.db.ty(adt.into()).subst(&substs) diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 8260bd15730..4974c565be1 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -144,8 +144,11 @@ impl ToChalk for Ty { } Ty::Param(id) => { let interned_id = db.intern_type_param_id(id); - PlaceholderIndex { ui: UniverseIndex::ROOT, idx: interned_id.as_intern_id().as_usize() } - .to_ty::() + PlaceholderIndex { + ui: UniverseIndex::ROOT, + idx: interned_id.as_intern_id().as_usize(), + } + .to_ty::() } Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), @@ -178,7 +181,9 @@ impl ToChalk for Ty { }, chalk_ir::TyData::Placeholder(idx) => { assert_eq!(idx.ui, UniverseIndex::ROOT); - let interned_id = crate::db::GlobalTypeParamId::from_intern_id(crate::salsa::InternId::from(idx.idx)); + let interned_id = crate::db::GlobalTypeParamId::from_intern_id( + crate::salsa::InternId::from(idx.idx), + ); Ty::Param(db.lookup_intern_type_param_id(interned_id)) } chalk_ir::TyData::Alias(proj) => { diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 8fa1838bd89..e307d958d83 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -2,6 +2,7 @@ //! query, but can't be computed directly from `*Data` (ie, which need a `db`). use std::sync::Arc; +use hir_def::generics::WherePredicateTarget; use hir_def::{ adt::VariantData, db::DefDatabase, @@ -12,7 +13,6 @@ use hir_def::{ AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, }; use hir_expand::name::{name, Name}; -use hir_def::generics::WherePredicateTarget; fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { let resolver = trait_.resolver(db); @@ -26,8 +26,12 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { .where_predicates .iter() .filter_map(|pred| match &pred.target { - WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => pred.bound.as_path(), - WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => pred.bound.as_path(), + WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => { + pred.bound.as_path() + } + WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => { + pred.bound.as_path() + } _ => None, }) .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { @@ -99,19 +103,35 @@ pub(crate) struct Generics { } impl Generics { - pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub(crate) fn iter<'a>( + &'a self, + ) -> impl Iterator + 'a { self.parent_generics .as_ref() .into_iter() - .flat_map(|it| it.params.types.iter().map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))) - .chain(self.params.types.iter().map(move |(local_id, p)| (TypeParamId { parent: self.def, local_id }, p))) + .flat_map(|it| { + it.params + .types + .iter() + .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p)) + }) + .chain( + self.params + .types + .iter() + .map(move |(local_id, p)| (TypeParamId { parent: self.def, local_id }, p)), + ) } - pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator + 'a { - self.parent_generics - .as_ref() - .into_iter() - .flat_map(|it| it.params.types.iter().map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))) + pub(crate) fn iter_parent<'a>( + &'a self, + ) -> impl Iterator + 'a { + self.parent_generics.as_ref().into_iter().flat_map(|it| { + it.params + .types + .iter() + .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p)) + }) } pub(crate) fn len(&self) -> usize { @@ -127,9 +147,24 @@ impl Generics { /// (self, type param list, impl trait) pub(crate) fn provenance_split(&self) -> (usize, usize, usize) { - let self_params = self.params.types.iter().filter(|(_, p)| p.provenance == TypeParamProvenance::TraitSelf).count(); - let list_params = self.params.types.iter().filter(|(_, p)| p.provenance == TypeParamProvenance::TypeParamList).count(); - let impl_trait_params = self.params.types.iter().filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait).count(); + let self_params = self + .params + .types + .iter() + .filter(|(_, p)| p.provenance == TypeParamProvenance::TraitSelf) + .count(); + let list_params = self + .params + .types + .iter() + .filter(|(_, p)| p.provenance == TypeParamProvenance::TypeParamList) + .count(); + let impl_trait_params = self + .params + .types + .iter() + .filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait) + .count(); (self_params, list_params, impl_trait_params) } From 6c70619b0126bc0e40bd9df39dcd6e711cac69c5 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 16:24:09 +0100 Subject: [PATCH 21/25] Deal better with implicit type parameters and argument lists --- crates/ra_hir_ty/src/infer/expr.rs | 8 +- crates/ra_hir_ty/src/lower.rs | 41 +++++----- crates/ra_hir_ty/src/tests/traits.rs | 108 +++++++++++++++++++++++++++ crates/ra_hir_ty/src/utils.rs | 7 +- 4 files changed, 138 insertions(+), 26 deletions(-) diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 8c360bcadcf..00ae3595360 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -647,8 +647,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { generic_args: Option<&GenericArgs>, receiver_ty: &Ty, ) -> Substs { - let (total_len, _parent_len, child_len) = - def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split()); + let (parent_params, self_params, type_params, impl_trait_params) = + def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split()); + assert_eq!(self_params, 0); // method shouldn't have another Self param + let total_len = parent_params + type_params + impl_trait_params; let mut substs = Vec::with_capacity(total_len); // Parent arguments are unknown, except for the receiver type if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { @@ -663,7 +665,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // handle provided type arguments if let Some(generic_args) = generic_args { // if args are provided, it should be all of them, but we can't rely on that - for arg in generic_args.args.iter().take(child_len) { + for arg in generic_args.args.iter().take(type_params) { match arg { GenericArg::Type(type_ref) => { let ty = self.make_ty(type_ref); diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 4168e750961..d2df3fe2b54 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -161,15 +161,19 @@ impl Ty { ImplTraitLoweringMode::Variable => { let idx = ctx.impl_trait_counter.get(); ctx.impl_trait_counter.set(idx + 1); - let (self_params, list_params, _impl_trait_params) = + let (parent_params, self_params, list_params, _impl_trait_params) = if let Some(def) = ctx.resolver.generic_def() { let generics = generics(ctx.db, def); generics.provenance_split() } else { - (0, 0, 0) + (0, 0, 0, 0) }; - // assert!((idx as usize) < impl_trait_params); // TODO return position impl trait - Ty::Bound(idx as u32 + self_params as u32 + list_params as u32) + Ty::Bound( + idx as u32 + + parent_params as u32 + + self_params as u32 + + list_params as u32, + ) } ImplTraitLoweringMode::Disallowed => { // FIXME: report error @@ -420,26 +424,23 @@ pub(super) fn substs_from_path_segment( ctx: &TyLoweringContext<'_, impl HirDatabase>, segment: PathSegment<'_>, def_generic: Option, - add_self_param: bool, + _add_self_param: bool, ) -> Substs { let mut substs = Vec::new(); let def_generics = def_generic.map(|def| generics(ctx.db, def.into())); - let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split()); - substs.extend(iter::repeat(Ty::Unknown).take(parent_len)); - if add_self_param { - // FIXME this add_self_param argument is kind of a hack: Traits have the - // Self type as an implicit first type parameter, but it can't be - // actually provided in the type arguments - // (well, actually sometimes it can, in the form of type-relative paths: `::default()`) - // TODO handle this using type param provenance (if there's a self param, and not one provided, add unknown) - substs.push(Ty::Unknown); - } + let (parent_params, self_params, type_params, impl_trait_params) = + def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); + substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); if let Some(generic_args) = &segment.args_and_bindings { + if !generic_args.has_self_type { + substs.extend(iter::repeat(Ty::Unknown).take(self_params)); + } + let expected_num = + if generic_args.has_self_type { self_params + type_params } else { type_params }; + let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; // if args are provided, it should be all of them, but we can't rely on that - let self_param_correction = if add_self_param { 1 } else { 0 }; - let child_len = child_len - self_param_correction; - for arg in generic_args.args.iter().take(child_len) { + for arg in generic_args.args.iter().skip(skip).take(expected_num) { match arg { GenericArg::Type(type_ref) => { let ty = Ty::from_hir(ctx, type_ref); @@ -448,9 +449,9 @@ pub(super) fn substs_from_path_segment( } } } + let total_len = parent_params + self_params + type_params + impl_trait_params; // add placeholders for args that were not provided - let supplied_params = substs.len(); - for _ in supplied_params..total_len { + for _ in substs.len()..total_len { substs.push(Ty::Unknown); } assert_eq!(substs.len(), total_len); diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 134cea8d86c..f90dadc08fd 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -905,6 +905,114 @@ fn test(x: impl Trait, y: &impl Trait) { ); } +#[test] +fn argument_impl_trait_type_args_1() { + assert_snapshot!( + infer_with_mismatches(r#" +trait Trait {} +trait Foo { + // this function has an implicit Self param, an explicit type param, + // and an implicit impl Trait param! + fn bar(x: impl Trait) -> T { loop {} } +} +fn foo(x: impl Trait) -> T { loop {} } +struct S; +impl Trait for S {} +struct F; +impl Foo for F {} + +fn test() { + Foo::bar(S); + ::bar(S); + F::bar(S); + Foo::bar::(S); + ::bar::(S); + + foo(S); + foo::(S); + foo::(S); // we should ignore the extraneous i32 +} +"#, true), + @r###" + [156; 157) 'x': impl Trait + [176; 187) '{ loop {} }': T + [178; 185) 'loop {}': ! + [183; 185) '{}': () + [200; 201) 'x': impl Trait + [220; 231) '{ loop {} }': T + [222; 229) 'loop {}': ! + [227; 229) '{}': () + [301; 510) '{ ... i32 }': () + [307; 315) 'Foo::bar': fn bar<{unknown}, {unknown}, S>(S) -> {unknown} + [307; 318) 'Foo::bar(S)': {unknown} + [316; 317) 'S': S + [324; 339) '::bar': fn bar(S) -> {unknown} + [324; 342) '(S) -> {unknown} + [348; 357) 'F::bar(S)': {unknown} + [355; 356) 'S': S + [363; 378) 'Foo::bar::': fn bar<{unknown}, u32, S>(S) -> u32 + [363; 381) 'Foo::b...32>(S)': u32 + [379; 380) 'S': S + [387; 409) '': fn bar(S) -> u32 + [387; 412) '(S)': u32 + [410; 411) 'S': S + [419; 422) 'foo': fn foo<{unknown}, S>(S) -> {unknown} + [419; 425) 'foo(S)': {unknown} + [423; 424) 'S': S + [431; 441) 'foo::': fn foo(S) -> u32 + [431; 444) 'foo::(S)': u32 + [442; 443) 'S': S + [450; 465) 'foo::': fn foo(S) -> u32 + [450; 468) 'foo::<...32>(S)': u32 + [466; 467) 'S': S + "### + ); +} + +#[test] +fn argument_impl_trait_type_args_2() { + assert_snapshot!( + infer_with_mismatches(r#" +trait Trait {} +struct S; +impl Trait for S {} +struct F; +impl F { + fn foo(self, x: impl Trait) -> (T, U) { loop {} } +} + +fn test() { + F.foo(S); + F::.foo(S); + F::.foo::(S); + F::.foo::(S); // extraneous argument should be ignored +} +"#, true), + @r###" + [88; 92) 'self': F + [94; 95) 'x': impl Trait + [119; 130) '{ loop {} }': (T, U) + [121; 128) 'loop {}': ! + [126; 128) '{}': () + [144; 284) '{ ...ored }': () + [150; 151) 'F': F<{unknown}> + [150; 158) 'F.foo(S)': ({unknown}, {unknown}) + [156; 157) 'S': S + [164; 172) 'F::': F + [164; 179) 'F::.foo(S)': (u32, {unknown}) + [177; 178) 'S': S + [185; 193) 'F::': F + [185; 207) 'F::(S)': (u32, i32) + [205; 206) 'S': S + [213; 221) 'F::': F + [213; 240) 'F::(S)': (u32, i32) + [238; 239) 'S': S + "### + ); +} + #[test] #[ignore] fn impl_trait() { diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index e307d958d83..508ae90465d 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -145,8 +145,9 @@ impl Generics { (parent + child, parent, child) } - /// (self, type param list, impl trait) - pub(crate) fn provenance_split(&self) -> (usize, usize, usize) { + /// (parent total, self param, type param list, impl trait) + pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize) { + let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); let self_params = self .params .types @@ -165,7 +166,7 @@ impl Generics { .iter() .filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait) .count(); - (self_params, list_params, impl_trait_params) + (parent, self_params, list_params, impl_trait_params) } pub(crate) fn param_idx(&self, param: TypeParamId) -> Option { From b0bb8622eea7cb447ebadb8b5fba43850305e913 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 16:39:48 +0100 Subject: [PATCH 22/25] Don't print implicit type args from impl Trait --- crates/ra_hir_ty/src/lib.rs | 13 ++++++++++--- crates/ra_hir_ty/src/tests/traits.rs | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 60c7fd0e5d9..68c2f0b061a 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -909,9 +909,16 @@ impl HirDisplay for ApplicationTy { } } if self.parameters.len() > 0 { - write!(f, "<")?; - f.write_joined(&*self.parameters.0, ", ")?; - write!(f, ">")?; + let generics = generics(f.db, def.into()); + let (parent_params, self_param, type_params, _impl_trait_params) = + generics.provenance_split(); + let total_len = parent_params + self_param + type_params; + // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? + if total_len > 0 { + write!(f, "<")?; + f.write_joined(&self.parameters.0[..total_len], ", ")?; + write!(f, ">")?; + } } write!(f, "(")?; f.write_joined(sig.params(), ", ")?; diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index f90dadc08fd..c6851fb6910 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -886,7 +886,7 @@ fn test(x: impl Trait, y: &impl Trait) { [224; 225) 'S': S(u16) -> S [224; 228) 'S(1)': S [226; 227) '1': u16 - [234; 237) 'bar': fn bar>(S) -> () + [234; 237) 'bar': fn bar(S) -> () [234; 240) 'bar(z)': () [238; 239) 'z': S [246; 247) 'x': impl Trait @@ -943,28 +943,28 @@ fn test() { [222; 229) 'loop {}': ! [227; 229) '{}': () [301; 510) '{ ... i32 }': () - [307; 315) 'Foo::bar': fn bar<{unknown}, {unknown}, S>(S) -> {unknown} + [307; 315) 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown} [307; 318) 'Foo::bar(S)': {unknown} [316; 317) 'S': S - [324; 339) '::bar': fn bar(S) -> {unknown} + [324; 339) '::bar': fn bar(S) -> {unknown} [324; 342) '(S) -> {unknown} + [348; 354) 'F::bar': fn bar(S) -> {unknown} [348; 357) 'F::bar(S)': {unknown} [355; 356) 'S': S - [363; 378) 'Foo::bar::': fn bar<{unknown}, u32, S>(S) -> u32 + [363; 378) 'Foo::bar::': fn bar<{unknown}, u32>(S) -> u32 [363; 381) 'Foo::b...32>(S)': u32 [379; 380) 'S': S - [387; 409) '': fn bar(S) -> u32 + [387; 409) '': fn bar(S) -> u32 [387; 412) '(S)': u32 [410; 411) 'S': S - [419; 422) 'foo': fn foo<{unknown}, S>(S) -> {unknown} + [419; 422) 'foo': fn foo<{unknown}>(S) -> {unknown} [419; 425) 'foo(S)': {unknown} [423; 424) 'S': S - [431; 441) 'foo::': fn foo(S) -> u32 + [431; 441) 'foo::': fn foo(S) -> u32 [431; 444) 'foo::(S)': u32 [442; 443) 'S': S - [450; 465) 'foo::': fn foo(S) -> u32 + [450; 465) 'foo::': fn foo(S) -> u32 [450; 468) 'foo::<...32>(S)': u32 [466; 467) 'S': S "### @@ -1794,11 +1794,11 @@ fn test() -> impl Trait { [229; 241) 'S(default())': S [231; 238) 'default': fn default() -> u32 [231; 240) 'default()': u32 - [247; 250) 'foo': fn foo>(S) -> () + [247; 250) 'foo': fn foo(S) -> () [247; 254) 'foo(s1)': () [251; 253) 's1': S [264; 265) 'x': i32 - [273; 276) 'bar': fn bar>(S) -> i32 + [273; 276) 'bar': fn bar(S) -> i32 [273; 290) 'bar(S(...lt()))': i32 [277; 278) 'S': S(i32) -> S [277; 289) 'S(default())': S From 6b9d05d1937f298df4197cebf862c3f644dd6778 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 18:17:08 +0100 Subject: [PATCH 23/25] Fix add_new assist (kind of) --- crates/ra_assists/src/handlers/add_new.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index 12d63b54da0..2701eddb80c 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs @@ -1,5 +1,5 @@ use format_buf::format; -use hir::InFile; +use hir::{Adt, InFile}; use join_to_string::join; use ra_syntax::{ ast::{ @@ -135,17 +135,22 @@ fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option; impl S {}` + // (we currently use the wrong type parameter) + // also we wouldn't want to use e.g. `impl S` + let same_ty = match blk.target_ty(db).as_adt() { + Some(def) => def == Adt::Struct(struct_def), + None => false, + }; let not_trait_impl = blk.target_trait(db).is_none(); if !(same_ty && not_trait_impl) { From 9d6061f3bb935c914a6d58df803dd42770f2f7e2 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 18:17:23 +0100 Subject: [PATCH 24/25] Fix some TODOs --- crates/ra_hir_ty/src/infer/expr.rs | 1 - crates/ra_hir_ty/src/lib.rs | 17 ++++++++++------- crates/ra_hir_ty/src/lower.rs | 10 +++++++--- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 00ae3595360..3c9c02d03ed 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -587,7 +587,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.write_method_resolution(tgt_expr, func); (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into()))) } - // TODO fix this None => (receiver_ty, Binders::new(0, Ty::Unknown), None), }; let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 68c2f0b061a..c5fe18c8550 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -287,17 +287,20 @@ pub enum Ty { /// trait and all its parameters are fully known. Projection(ProjectionTy), - /// A type parameter; for example, `T` in `fn f(x: T) {} - // TODO fix documentation + /// A placeholder for a type parameter; for example, `T` in `fn f(x: T) + /// {}` when we're type-checking the body of that function. In this + /// situation, we know this stands for *some* type, but don't know the exact + /// type. Param(TypeParamId), - /// A bound type variable. Used during trait resolution to represent Chalk - /// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type. - // TODO fix documentation + /// A bound type variable. This is used in various places: when representing + /// some polymorphic type like the type of function `fn f`, the type + /// parameters get turned into variables; during trait resolution, inference + /// variables get turned into bound variables and back; and in `Dyn` the + /// `Self` type is represented with a bound variable as well. Bound(u32), - /// A type variable used during type checking. Not to be confused with a - /// type parameter. + /// A type variable used during type checking. Infer(InferTy), /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust). diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index d2df3fe2b54..c68c5852be7 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -890,9 +890,13 @@ pub(crate) fn ty_query(db: &impl HirDatabase, def: TyDefId) -> Binders { } } -pub(crate) fn ty_recover(_db: &impl HirDatabase, _cycle: &[String], _def: &TyDefId) -> Binders { - // TODO still need correct number of binders here - Binders::new(0, Ty::Unknown) +pub(crate) fn ty_recover(db: &impl HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders { + let num_binders = match *def { + TyDefId::BuiltinType(_) => 0, + TyDefId::AdtId(it) => generics(db, it.into()).len(), + TyDefId::TypeAliasId(it) => generics(db, it.into()).len(), + }; + Binders::new(num_binders, Ty::Unknown) } pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Binders { From eefe02ce6e1750b771cf99125429358e87485745 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 7 Feb 2020 18:27:54 +0100 Subject: [PATCH 25/25] Add two more tests --- crates/ra_hir_ty/src/tests/traits.rs | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index c6851fb6910..17611ddbfa4 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1013,6 +1013,31 @@ fn test() { ); } +#[test] +fn argument_impl_trait_to_fn_pointer() { + assert_snapshot!( + infer_with_mismatches(r#" +trait Trait {} +fn foo(x: impl Trait) { loop {} } +struct S; +impl Trait for S {} + +fn test() { + let f: fn(S) -> () = foo; +} +"#, true), + @r###" + [23; 24) 'x': impl Trait + [38; 49) '{ loop {} }': () + [40; 47) 'loop {}': ! + [45; 47) '{}': () + [91; 124) '{ ...foo; }': () + [101; 102) 'f': fn(S) -> () + [118; 121) 'foo': fn foo(S) -> () + "### + ); +} + #[test] #[ignore] fn impl_trait() { @@ -1376,6 +1401,32 @@ fn test(x: T, y: U) { ); } +#[test] +fn super_trait_impl_trait_method_resolution() { + assert_snapshot!( + infer(r#" +mod foo { + trait SuperTrait { + fn foo(&self) -> u32 {} + } +} +trait Trait1: foo::SuperTrait {} + +fn test(x: &impl Trait1) { + x.foo(); +} +"#), + @r###" + [50; 54) 'self': &Self + [63; 65) '{}': () + [116; 117) 'x': &impl Trait1 + [133; 149) '{ ...o(); }': () + [139; 140) 'x': &impl Trait1 + [139; 146) 'x.foo()': u32 + "### + ); +} + #[test] fn super_trait_cycle() { // This just needs to not crash