]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_ty/src/lower.rs
Simplify
[rust.git] / crates / hir_ty / src / lower.rs
index 2eb9a21ddd2c793830ae599eae699544bb2f22a6..3734eb1013106e5db1d5f65a3210c17f8d1de7f8 100644 (file)
@@ -66,8 +66,8 @@ pub struct TyLoweringContext<'a> {
     /// Splitting this up would be a possible fix.
     opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
     expander: RefCell<Option<Expander>>,
-    /// Keeps tracking types with explicit `?Sized` bounds.
-    unsized_types: RefCell<FxHashSet<Ty>>,
+    /// Tracks types with explicit `?Sized` bounds.
+    pub(crate) unsized_types: RefCell<FxHashSet<Ty>>,
 }
 
 impl<'a> TyLoweringContext<'a> {
@@ -226,6 +226,10 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                     ImplTraitLoweringMode::Opaque => {
                         let idx = self.impl_trait_counter.get();
                         self.impl_trait_counter.set(idx + 1);
+                        let func = match self.resolver.generic_def() {
+                            Some(GenericDefId::FunctionId(f)) => f,
+                            _ => panic!("opaque impl trait lowering in non-function"),
+                        };
 
                         assert!(idx as usize == self.opaque_type_data.borrow().len());
                         // this dance is to make sure the data is in the right
@@ -245,14 +249,10 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                         // away instead of two.
                         let actual_opaque_type_data = self
                             .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
-                                ctx.lower_impl_trait(bounds)
+                                ctx.lower_impl_trait(bounds, func)
                             });
                         self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
 
-                        let func = match self.resolver.generic_def() {
-                            Some(GenericDefId::FunctionId(f)) => f,
-                            _ => panic!("opaque impl trait lowering in non-function"),
-                        };
                         let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
                         let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
                         let generics = generics(self.db.upcast(), func.into());
@@ -307,17 +307,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 {
@@ -387,15 +382,17 @@ pub(crate) fn lower_ty_relative_path(
         res: Option<TypeNs>,
         remaining_segments: PathSegments<'_>,
     ) -> (Ty, Option<TypeNs>) {
-        if remaining_segments.len() == 1 {
-            // resolve unselected assoc types
-            let segment = remaining_segments.first().unwrap();
-            (self.select_associated_type(res, segment), None)
-        } else if remaining_segments.len() > 1 {
-            // FIXME report error (ambiguous associated type)
-            (TyKind::Error.intern(&Interner), None)
-        } else {
-            (ty, res)
+        match remaining_segments.len() {
+            0 => (ty, res),
+            1 => {
+                // resolve unselected assoc types
+                let segment = remaining_segments.first().unwrap();
+                (self.select_associated_type(res, segment), None)
+            }
+            _ => {
+                // FIXME report error (ambiguous associated type)
+                (TyKind::Error.intern(&Interner), None)
+            }
         }
     }
 
@@ -408,54 +405,60 @@ pub(crate) fn lower_partly_resolved_path(
     ) -> (Ty, Option<TypeNs>) {
         let ty = match resolution {
             TypeNs::TraitId(trait_) => {
-                // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there
-                let self_ty = if remaining_segments.len() == 0 {
-                    Some(
-                        TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
-                            .intern(&Interner),
-                    )
-                } else {
-                    None
-                };
-                let trait_ref =
-                    self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty);
-                let ty = if remaining_segments.len() == 1 {
-                    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 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);
             }
@@ -796,7 +799,7 @@ pub(crate) fn lower_type_bound(
                     .and_then(|krate| self.db.lang_item(krate, "sized".into()))
                     .and_then(|lang_item| lang_item.as_trait());
                 // Don't lower associated type bindings as the only possible relaxed trait bound
-                // `?Sized` has none of them.
+                // `?Sized` has no of them.
                 // If we got another trait here ignore the bound completely.
                 let trait_id = self
                     .lower_trait_ref_from_path(path, Some(self_ty.clone()))
@@ -828,7 +831,9 @@ fn assoc_type_bindings_from_type_bound(
         trait_ref: TraitRef,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
         let last_segment = match bound {
-            TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => path.segments().last(),
+            TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
+                path.segments().last()
+            }
             TypeBound::Path(_, TraitBoundModifier::Maybe)
             | TypeBound::Error
             | TypeBound::Lifetime(_) => None,
@@ -871,13 +876,39 @@ fn assoc_type_bindings_from_type_bound(
             })
     }
 
-    fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>]) -> ReturnTypeImplTrait {
+    fn lower_impl_trait(
+        &self,
+        bounds: &[Interned<TypeBound>],
+        func: FunctionId,
+    ) -> ReturnTypeImplTrait {
         cov_mark::hit!(lower_rpit);
         let self_ty =
             TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner);
         let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-            bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect()
+            let mut predicates: Vec<_> = bounds
+                .iter()
+                .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
+                .collect();
+
+            if !ctx.unsized_types.borrow().contains(&self_ty) {
+                let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
+                let sized_trait = ctx
+                    .db
+                    .lang_item(krate, "sized".into())
+                    .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 {
+                        trait_id,
+                        substitution: Substitution::from1(&Interner, self_ty.clone()),
+                    });
+                    crate::wrap_empty_binders(clause)
+                });
+                predicates.extend(sized_clause.into_iter());
+                predicates.shrink_to_fit();
+            }
+            predicates
         });
+
         ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
     }
 }
@@ -996,7 +1027,7 @@ pub(crate) fn generic_predicates_for_param_query(
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let generics = generics(db.upcast(), param_id.parent);
-    resolver
+    let mut predicates: Vec<_> = resolver
         .where_predicates_in_scope()
         // we have to filter out all other predicates *first*, before attempting to lower them
         .filter(|pred| match pred {
@@ -1010,7 +1041,15 @@ pub(crate) fn generic_predicates_for_param_query(
             WherePredicate::Lifetime { .. } => false,
         })
         .flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
-        .collect()
+        .collect();
+
+    let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
+    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+    let implicitly_sized_predicates =
+        implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
+            .map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
+    predicates.extend(implicitly_sized_predicates);
+    predicates.into()
 }
 
 pub(crate) fn generic_predicates_for_param_recover(
@@ -1036,7 +1075,7 @@ pub(crate) fn trait_environment_query(
                 traits_in_scope
                     .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
             }
-            let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
+            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
             clauses.push(program_clause.into_from_env_clause(&Interner));
         }
     }
@@ -1063,6 +1102,15 @@ pub(crate) fn trait_environment_query(
         clauses.push(program_clause.into_from_env_clause(&Interner));
     }
 
+    let subst = generics(db.upcast(), def).type_params_subst(db);
+    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+    let implicitly_sized_clauses =
+        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| {
+            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
+            program_clause.into_from_env_clause(&Interner)
+        });
+    clauses.extend(implicitly_sized_clauses);
+
     let krate = def.module(db.upcast()).krate();
 
     let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses);
@@ -1085,34 +1133,43 @@ pub(crate) fn generic_predicates_query(
         .flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
         .collect::<Vec<_>>();
 
-    // Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
-    // Exception is Self of a trait.
-    let is_trait_def = matches!(def, GenericDefId::TraitId(..));
+    let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
     let explicitly_unsized_tys = ctx.unsized_types.into_inner();
-    let subtsts = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
-    let generic_args = &subtsts.as_slice(&Interner)[is_trait_def as usize..];
+    let implicitly_sized_predicates =
+        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
+            .map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
+    predicates.extend(implicitly_sized_predicates);
+    predicates.into()
+}
+
+/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
+/// Exception is Self of a trait def.
+fn implicitly_sized_clauses<'a>(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+    explicitly_unsized_tys: &'a FxHashSet<Ty>,
+    substitution: &'a Substitution,
+    resolver: &Resolver,
+) -> impl Iterator<Item = WhereClause> + 'a {
+    let is_trait_def = matches!(def, GenericDefId::TraitId(..));
+    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(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
-    let sized_predicates = sized_trait
-        .into_iter()
-        .flat_map(|sized_trait| {
-            let implicitly_sized_tys = generic_args
-                .iter()
-                .filter_map(|generic_arg| generic_arg.ty(&Interner))
-                .filter(|&self_ty| !explicitly_unsized_tys.contains(self_ty));
-            implicitly_sized_tys.map(move |self_ty| {
-                WhereClause::Implemented(TraitRef {
-                    trait_id: sized_trait,
-                    substitution: Substitution::from1(&Interner, self_ty.clone()),
-                })
+
+    sized_trait.into_iter().flat_map(move |sized_trait| {
+        let implicitly_sized_tys = generic_args
+            .iter()
+            .filter_map(|generic_arg| generic_arg.ty(&Interner))
+            .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty));
+        implicitly_sized_tys.map(move |self_ty| {
+            WhereClause::Implemented(TraitRef {
+                trait_id: sized_trait,
+                substitution: Substitution::from1(&Interner, self_ty.clone()),
             })
         })
-        .map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
-
-    predicates.extend(sized_predicates);
-    predicates.into()
+    })
 }
 
 /// Resolve the default type params from generics
@@ -1375,8 +1432,13 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders
 }
 
 pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
+    let impl_loc = impl_id.lookup(db.upcast());
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
+    let _cx = stdx::panic_context::enter(format!(
+        "impl_self_ty_query({:?} -> {:?} -> {:?})",
+        impl_id, impl_loc, impl_data
+    ));
     let generics = generics(db.upcast(), impl_id.into());
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
@@ -1402,8 +1464,13 @@ pub(crate) fn impl_self_ty_recover(
 }
 
 pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
+    let impl_loc = impl_id.lookup(db.upcast());
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
+    let _cx = stdx::panic_context::enter(format!(
+        "impl_trait_query({:?} -> {:?} -> {:?})",
+        impl_id, impl_loc, impl_data
+    ));
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();