]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_ty/src/lower.rs
Merge #10987
[rust.git] / crates / hir_ty / src / lower.rs
index 13785e3a6cdf86d550ae07b2528363bc3696ae35..7373c9eb8b4b84c143f25cabd295c0abe91b9137 100644 (file)
@@ -19,8 +19,8 @@
     path::{GenericArg, Path, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
-    AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
-    GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
+    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
     TypeAliasId, TypeParamId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
@@ -28,8 +28,9 @@
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use stdx::impl_from;
-use syntax::ast;
+use syntax::{ast, SmolStr};
 
+use crate::all_super_traits;
 use crate::{
     consteval,
     db::HirDatabase,
@@ -95,9 +96,9 @@ pub fn with_debruijn<T>(
         debruijn: DebruijnIndex,
         f: impl FnOnce(&TyLoweringContext) -> T,
     ) -> T {
-        let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
-        let expander = self.expander.replace(None);
-        let unsized_types = self.unsized_types.replace(Default::default());
+        let opaque_ty_data_vec = self.opaque_type_data.take();
+        let expander = self.expander.take();
+        let unsized_types = self.unsized_types.take();
         let new_ctx = Self {
             in_binders: debruijn,
             impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
@@ -307,17 +308,12 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                     let mut expander = self.expander.borrow_mut();
                     if expander.is_some() {
                         (Some(expander), false)
+                    } else if let Some(module_id) = self.resolver.module() {
+                        *expander =
+                            Some(Expander::new(self.db.upcast(), macro_call.file_id, module_id));
+                        (Some(expander), true)
                     } else {
-                        if let Some(module_id) = self.resolver.module() {
-                            *expander = Some(Expander::new(
-                                self.db.upcast(),
-                                macro_call.file_id,
-                                module_id,
-                            ));
-                            (Some(expander), true)
-                        } else {
-                            (None, false)
-                        }
+                        (None, false)
                     }
                 };
                 let ty = if let Some(mut expander) = expander {
@@ -373,10 +369,9 @@ fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeParamId> {
                 Some((it, None)) => it,
                 _ => return None,
             };
-        if let TypeNs::GenericParam(param_id) = resolution {
-            Some(param_id)
-        } else {
-            None
+        match resolution {
+            TypeNs::GenericParam(param_id) => Some(param_id),
+            _ => None,
         }
     }
 
@@ -410,52 +405,60 @@ pub(crate) fn lower_partly_resolved_path(
     ) -> (Ty, Option<TypeNs>) {
         let ty = match resolution {
             TypeNs::TraitId(trait_) => {
-                let ty = if remaining_segments.len() == 1 {
-                    let trait_ref =
-                        self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
-                    let segment = remaining_segments.first().unwrap();
-                    let found = self
-                        .db
-                        .trait_data(trait_ref.hir_trait_id())
-                        .associated_type_by_name(segment.name);
-                    match found {
-                        Some(associated_ty) => {
-                            // FIXME handle type parameters on the segment
-                            TyKind::Alias(AliasTy::Projection(ProjectionTy {
-                                associated_ty_id: to_assoc_type_id(associated_ty),
-                                substitution: trait_ref.substitution,
-                            }))
-                            .intern(&Interner)
-                        }
-                        None => {
-                            // FIXME: report error (associated type not found)
-                            TyKind::Error.intern(&Interner)
+                let ty = match remaining_segments.len() {
+                    1 => {
+                        let trait_ref =
+                            self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
+                        let segment = remaining_segments.first().unwrap();
+                        let found = self
+                            .db
+                            .trait_data(trait_ref.hir_trait_id())
+                            .associated_type_by_name(segment.name);
+                        match found {
+                            Some(associated_ty) => {
+                                // FIXME handle type parameters on the segment
+                                TyKind::Alias(AliasTy::Projection(ProjectionTy {
+                                    associated_ty_id: to_assoc_type_id(associated_ty),
+                                    substitution: trait_ref.substitution,
+                                }))
+                                .intern(&Interner)
+                            }
+                            None => {
+                                // FIXME: report error (associated type not found)
+                                TyKind::Error.intern(&Interner)
+                            }
                         }
                     }
-                } else if remaining_segments.len() > 1 {
-                    // FIXME report error (ambiguous associated type)
-                    TyKind::Error.intern(&Interner)
-                } else {
-                    let self_ty = Some(
-                        TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
-                            .intern(&Interner),
-                    );
-                    let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                        ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
-                    });
-                    let dyn_ty = DynTy {
-                        bounds: crate::make_only_type_binders(
-                            1,
-                            QuantifiedWhereClauses::from_iter(
-                                &Interner,
-                                Some(crate::wrap_empty_binders(WhereClause::Implemented(
-                                    trait_ref,
-                                ))),
+                    0 => {
+                        let self_ty = Some(
+                            TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
+                                .intern(&Interner),
+                        );
+                        let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
+                            ctx.lower_trait_ref_from_resolved_path(
+                                trait_,
+                                resolved_segment,
+                                self_ty,
+                            )
+                        });
+                        let dyn_ty = DynTy {
+                            bounds: crate::make_only_type_binders(
+                                1,
+                                QuantifiedWhereClauses::from_iter(
+                                    &Interner,
+                                    Some(crate::wrap_empty_binders(WhereClause::Implemented(
+                                        trait_ref,
+                                    ))),
+                                ),
                             ),
-                        ),
-                        lifetime: static_lifetime(),
-                    };
-                    TyKind::Dyn(dyn_ty).intern(&Interner)
+                            lifetime: static_lifetime(),
+                        };
+                        TyKind::Dyn(dyn_ty).intern(&Interner)
+                    }
+                    _ => {
+                        // FIXME report error (ambiguous associated type)
+                        TyKind::Error.intern(&Interner)
+                    }
                 };
                 return (ty, None);
             }
@@ -528,9 +531,10 @@ pub(crate) fn lower_path(&self, path: &Path) -> (Ty, Option<TypeNs>) {
 
     fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
         if let Some(res) = res {
-            let ty = associated_type_shorthand_candidates(
+            let ty = named_associated_type_shorthand_candidates(
                 self.db,
                 res,
+                Some(segment.name.clone()),
                 move |name, t, associated_ty| {
                     if name == segment.name {
                         let substs = match self.type_param_mode {
@@ -552,16 +556,16 @@ fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>)
                         // associated_type_shorthand_candidates does not do that
                         let substs = substs.shifted_in_from(&Interner, self.in_binders);
                         // FIXME handle type parameters on the segment
-                        return Some(
+                        Some(
                             TyKind::Alias(AliasTy::Projection(ProjectionTy {
                                 associated_ty_id: to_assoc_type_id(associated_ty),
                                 substitution: substs,
                             }))
                             .intern(&Interner),
-                        );
+                        )
+                    } else {
+                        None
                     }
-
-                    None
                 },
             );
 
@@ -611,7 +615,7 @@ pub(super) fn substs_from_path(
                 // `Option::None::<T>` are both allowed (though the former is
                 // preferred). See also `def_ids_for_path_segments` in rustc.
                 let len = path.segments().len();
-                let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
+                let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
                 let segment = match penultimate {
                     Some(segment) if segment.args_and_bindings.is_some() => segment,
                     _ => last,
@@ -793,7 +797,7 @@ pub(crate) fn lower_type_bound(
                 let sized_trait = self
                     .resolver
                     .krate()
-                    .and_then(|krate| self.db.lang_item(krate, "sized".into()))
+                    .and_then(|krate| self.db.lang_item(krate, SmolStr::new_inline("sized")))
                     .and_then(|lang_item| lang_item.as_trait());
                 // Don't lower associated type bindings as the only possible relaxed trait bound
                 // `?Sized` has no of them.
@@ -837,8 +841,8 @@ fn assoc_type_bindings_from_type_bound(
         };
         last_segment
             .into_iter()
-            .flat_map(|segment| segment.args_and_bindings.into_iter())
-            .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
+            .filter_map(|segment| segment.args_and_bindings)
+            .flat_map(|args_and_bindings| &args_and_bindings.bindings)
             .flat_map(move |binding| {
                 let found = associated_type_by_name_including_super_traits(
                     self.db,
@@ -846,14 +850,14 @@ fn assoc_type_bindings_from_type_bound(
                     &binding.name,
                 );
                 let (super_trait_ref, associated_ty) = match found {
-                    None => return SmallVec::<[QuantifiedWhereClause; 1]>::new(),
+                    None => return SmallVec::new(),
                     Some(t) => t,
                 };
                 let projection_ty = ProjectionTy {
                     associated_ty_id: to_assoc_type_id(associated_ty),
                     substitution: super_trait_ref.substitution,
                 };
-                let mut preds = SmallVec::with_capacity(
+                let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = &binding.type_ref {
@@ -891,7 +895,7 @@ fn lower_impl_trait(
                 let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
                 let sized_trait = ctx
                     .db
-                    .lang_item(krate, "sized".into())
+                    .lang_item(krate, SmolStr::new_inline("sized"))
                     .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
                 let sized_clause = sized_trait.map(|trait_id| {
                     let clause = WhereClause::Implemented(TraitRef {
@@ -932,6 +936,15 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig
 pub fn associated_type_shorthand_candidates<R>(
     db: &dyn HirDatabase,
     res: TypeNs,
+    cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
+) -> Option<R> {
+    named_associated_type_shorthand_candidates(db, res, None, cb)
+}
+
+fn named_associated_type_shorthand_candidates<R>(
+    db: &dyn HirDatabase,
+    res: TypeNs,
+    assoc_name: Option<Name>,
     mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
 ) -> Option<R> {
     let mut search = |t| {
@@ -956,7 +969,7 @@ pub fn associated_type_shorthand_candidates<R>(
             db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
         ),
         TypeNs::GenericParam(param_id) => {
-            let predicates = db.generic_predicates_for_param(param_id);
+            let predicates = db.generic_predicates_for_param(param_id, assoc_name);
             let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
                 // FIXME: how to correctly handle higher-ranked bounds here?
                 WhereClause::Implemented(tr) => search(
@@ -1019,6 +1032,7 @@ pub(crate) fn field_types_query(
 pub(crate) fn generic_predicates_for_param_query(
     db: &dyn HirDatabase,
     param_id: TypeParamId,
+    assoc_name: Option<Name>,
 ) -> Arc<[Binders<QuantifiedWhereClause>]> {
     let resolver = param_id.parent.resolver(db.upcast());
     let ctx =
@@ -1028,13 +1042,46 @@ 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 {
-            WherePredicate::ForLifetime { target, .. }
-            | WherePredicate::TypeBound { target, .. } => match target {
-                WherePredicateTypeTarget::TypeRef(type_ref) => {
-                    ctx.lower_ty_only_param(type_ref) == Some(param_id)
+            WherePredicate::ForLifetime { target, bound, .. }
+            | WherePredicate::TypeBound { target, bound, .. } => {
+                match target {
+                    WherePredicateTypeTarget::TypeRef(type_ref) => {
+                        if ctx.lower_ty_only_param(type_ref) != Some(param_id) {
+                            return false;
+                        }
+                    }
+                    WherePredicateTypeTarget::TypeParam(local_id) => {
+                        if *local_id != param_id.local_id {
+                            return false;
+                        }
+                    }
+                };
+
+                match &**bound {
+                    TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
+                        // Only lower the bound if the trait could possibly define the associated
+                        // type we're looking for.
+
+                        let assoc_name = match &assoc_name {
+                            Some(it) => it,
+                            None => return true,
+                        };
+                        let tr = match resolver
+                            .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
+                        {
+                            Some(TypeNs::TraitId(tr)) => tr,
+                            _ => return false,
+                        };
+
+                        all_super_traits(db.upcast(), tr).iter().any(|tr| {
+                            db.trait_data(*tr).items.iter().any(|(name, item)| {
+                                matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
+                            })
+                        })
+                    }
+                    TypeBound::Lifetime(_) | TypeBound::Error => false,
                 }
-                WherePredicateTypeTarget::TypeParam(local_id) => *local_id == param_id.local_id,
-            },
+            }
             WherePredicate::Lifetime { .. } => false,
         })
         .flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
@@ -1053,6 +1100,7 @@ pub(crate) fn generic_predicates_for_param_recover(
     _db: &dyn HirDatabase,
     _cycle: &[String],
     _param_id: &TypeParamId,
+    _assoc_name: &Option<Name>,
 ) -> Arc<[Binders<QuantifiedWhereClause>]> {
     Arc::new([])
 }
@@ -1077,7 +1125,7 @@ pub(crate) fn trait_environment_query(
         }
     }
 
-    let container: Option<AssocContainerId> = match def {
+    let container: Option<ItemContainerId> = match def {
         // FIXME: is there a function for this?
         GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container),
         GenericDefId::AdtId(_) => None,
@@ -1087,7 +1135,7 @@ pub(crate) fn trait_environment_query(
         GenericDefId::EnumVariantId(_) => None,
         GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container),
     };
-    if let Some(AssocContainerId::TraitId(trait_id)) = container {
+    if let Some(ItemContainerId::TraitId(trait_id)) = container {
         // add `Self: Trait<T1, T2, ...>` to the environment in trait
         // function default implementations (and speculative code
         // inside consts or type aliases)
@@ -1152,7 +1200,7 @@ fn implicitly_sized_clauses<'a>(
     let generic_args = &substitution.as_slice(&Interner)[is_trait_def as usize..];
     let sized_trait = resolver
         .krate()
-        .and_then(|krate| db.lang_item(krate, "sized".into()))
+        .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
         .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 
     sized_trait.into_iter().flat_map(move |sized_trait| {