Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer.rs')
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 431 |
1 files changed, 257 insertions, 174 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index e7f3827d84..e338548626 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -29,22 +29,28 @@ mod path; mod place_op; pub(crate) mod unify; -use std::{cell::OnceCell, convert::identity, fmt, ops::Deref}; +use std::{ + cell::{OnceCell, RefCell}, + convert::identity, + fmt, + hash::Hash, + ops::Deref, +}; use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - AdtId, AssocItemId, AttrDefId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId, - FieldId, FunctionId, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, TraitId, - TupleFieldId, TupleId, TypeOrConstParamId, VariantId, + AdtId, AssocItemId, AttrDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, + FunctionId, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, StaticId, TraitId, + TupleFieldId, TupleId, VariantId, attrs::AttrFlags, - expr_store::{Body, ExpressionStore, HygieneId, RootExprOrigin, path::Path}, + expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, - type_ref::{ConstRef, LifetimeRefId, TypeRef, TypeRefId}, + type_ref::{LifetimeRefId, TypeRef, TypeRefId}, unstable_features::UnstableFeatures, }; use hir_expand::{mod_path::ModPath, name::Name}; @@ -54,8 +60,8 @@ use macros::{TypeFoldable, TypeVisitable}; use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_type_ir::{ - AliasTyKind, TypeFoldable, - inherent::{Const as _, IntoKind, Ty as _}, + AliasTyKind, TypeFoldable, TypeVisitableExt, + inherent::{IntoKind, Ty as _}, }; use smallvec::SmallVec; use span::Edition; @@ -63,10 +69,13 @@ use stdx::never; use thin_vec::ThinVec; use crate::{ - ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, Span, TargetFeatures, + ImplTraitId, IncorrectGenericsLenKind, InferBodyId, PathLoweringDiagnostic, Span, + TargetFeatures, closure_analysis::PlaceBase, collect_type_inference_vars, - db::{HirDatabase, InternedOpaqueTyId}, + consteval::{create_anon_const, path_to_const}, + db::{AnonConstId, GeneralConstId, HirDatabase, InternedOpaqueTyId}, + generics::Generics, infer::{ callee::DeferredCallResolution, closure::analysis::{ @@ -84,8 +93,8 @@ use crate::{ }, method_resolution::CandidateId, next_solver::{ - AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArg, - StoredGenericArgs, StoredTy, StoredTys, Term, Ty, TyKind, Tys, + AliasTy, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, Region, + StoredGenericArg, StoredGenericArgs, StoredTy, StoredTys, Term, Ty, TyKind, Tys, abi::Safety, infer::{InferCtxt, ObligationInspector, traits::ObligationCause}, }, @@ -116,8 +125,15 @@ pub fn infer_query_with_inspect<'db>( let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); let body = Body::of(db, def); - let mut ctx = - InferenceContext::new(db, ExpressionStoreOwnerId::Body(def), &body.store, resolver); + let mut ctx = InferenceContext::new( + db, + InferBodyId::DefWithBodyId(def), + ExpressionStoreOwnerId::Body(def), + def.generic_def(db), + &body.store, + resolver, + true, + ); if let Some(inspect) = inspect { ctx.table.infer_ctxt.attach_obligation_inspector(inspect); @@ -126,7 +142,7 @@ pub fn infer_query_with_inspect<'db>( match def { DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param, &body.params), DefWithBodyId::ConstId(c) => ctx.collect_const(c, ConstSignature::of(db, c)), - DefWithBodyId::StaticId(s) => ctx.collect_static(StaticSignature::of(db, s)), + DefWithBodyId::StaticId(s) => ctx.collect_static(s, StaticSignature::of(db, s)), DefWithBodyId::VariantId(v) => { ctx.return_ty = match EnumSignature::variant_body_type(db, v.lookup(db).parent) { hir_def::layout::IntegerType::Pointer(signed) => match signed { @@ -167,91 +183,38 @@ fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> I } } -/// Infer types for all const expressions in an item's signature. -/// -/// This handles const expressions that appear in type positions within a generic -/// item's signature, such as array lengths (`[T; N]`) and const generic arguments -/// (`Foo<{ expr }>`). Each root expression is inferred independently within -/// a shared `InferenceContext`, accumulating results into a single `InferenceResult`. -fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { - let _p = tracing::info_span!("infer_signature_query").entered(); - let store = ExpressionStore::of(db, def.into()); - let mut roots = store.expr_roots_with_origins().peekable(); - let Some(_) = roots.peek() else { - return InferenceResult::new(crate::next_solver::default_types(db).types.error); - }; - - let resolver = def.resolver(db); - let owner = ExpressionStoreOwnerId::Signature(def); - - let mut ctx = InferenceContext::new(db, owner, store, resolver); - - for (root_expr, origin) in roots { - let expected = match origin { - // Array lengths are always `usize`. - RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), - // Const parameter default: look up the param's declared type. - RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty( - ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), - )), - // Path const generic args: determining the expected type requires - // path resolution. - // FIXME - RootExprOrigin::GenericArgsPath => Expectation::None, - RootExprOrigin::BodyRoot => Expectation::None, - }; - ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); - } +/// Infer types for an anonymous const expression. +fn infer_anon_const_query(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { + let _p = tracing::info_span!("infer_anon_const_query").entered(); + let loc = def.loc(db); + let store_owner = loc.owner; + let store = ExpressionStore::of(db, store_owner); + + let resolver = store_owner.resolver(db); + + let mut ctx = InferenceContext::new( + db, + InferBodyId::AnonConstId(def), + store_owner, + loc.owner.generic_def(db), + store, + resolver, + loc.allow_using_generic_params, + ); + + ctx.infer_expr( + loc.expr, + &Expectation::has_type(loc.ty.get().instantiate_identity()), + ExprIsRead::Yes, + ); infer_finalize(ctx) } -fn infer_variant_fields_query(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { - let _p = tracing::info_span!("infer_variant_fields_query").entered(); - let store = ExpressionStore::of(db, def.into()); - let mut roots = store.expr_roots_with_origins().peekable(); - let Some(_) = roots.peek() else { - return InferenceResult::new(crate::next_solver::default_types(db).types.error); - }; - - let resolver = def.resolver(db); - let owner = ExpressionStoreOwnerId::VariantFields(def); - - let mut ctx = InferenceContext::new(db, owner, store, resolver); - - for (root_expr, origin) in roots { - let expected = match origin { - // Array lengths are always `usize`. - RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), - // unreachable - RootExprOrigin::ConstParam(_) => Expectation::None, - // Path const generic args: determining the expected type requires - // path resolution. - // FIXME - RootExprOrigin::GenericArgsPath => Expectation::None, - RootExprOrigin::BodyRoot => Expectation::None, - }; - ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); - } - - infer_finalize(ctx) -} - -fn infer_signature_cycle_result( - db: &dyn HirDatabase, - _: salsa::Id, - _: GenericDefId, -) -> InferenceResult { - InferenceResult { - has_errors: true, - ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) - } -} - -fn infer_variant_fields_cycle_result( +fn infer_anon_const_cycle_result( db: &dyn HirDatabase, _: salsa::Id, - _: VariantId, + _: AnonConstId, ) -> InferenceResult { InferenceResult { has_errors: true, @@ -285,6 +248,8 @@ fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { ctx.handle_opaque_type_uses(); + ctx.merge_anon_consts(); + ctx.resolve_all() } @@ -745,6 +710,8 @@ pub struct InferenceResult { pub(crate) coercion_casts: FxHashSet<ExprId>, pub closures_data: FxHashMap<ExprId, ClosureData>, + + defined_anon_consts: ThinVec<AnonConstId>, } #[derive(Clone, PartialEq, Eq, Debug, Default)] @@ -976,30 +943,21 @@ impl InferenceResult { /// Returns an `InferenceResult` containing type information for array lengths, /// const generic arguments, and other const expressions appearing in type /// positions within the item's signature. - #[salsa::tracked(returns(ref), cycle_result = infer_signature_cycle_result)] - fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { - infer_signature_query(db, def) + #[salsa::tracked(returns(ref), cycle_result = infer_anon_const_cycle_result)] + fn for_anon_const(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { + infer_anon_const_query(db, def) } - #[salsa::tracked(returns(ref), cycle_result = infer_variant_fields_cycle_result)] - fn for_variant_fields(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { - infer_variant_fields_query(db, def) - } -} - -impl InferenceResult { - pub fn of(db: &dyn HirDatabase, def: impl Into<ExpressionStoreOwnerId>) -> &InferenceResult { + #[inline] + pub fn of(db: &dyn HirDatabase, def: impl Into<InferBodyId>) -> &InferenceResult { match def.into() { - ExpressionStoreOwnerId::Signature(generic_def_id) => { - Self::for_signature(db, generic_def_id) - } - ExpressionStoreOwnerId::Body(def_with_body_id) => Self::for_body(db, def_with_body_id), - ExpressionStoreOwnerId::VariantFields(variant_id) => { - Self::for_variant_fields(db, variant_id) - } + InferBodyId::DefWithBodyId(it) => InferenceResult::for_body(db, it), + InferBodyId::AnonConstId(it) => InferenceResult::for_anon_const(db, it), } } +} +impl InferenceResult { fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -1022,6 +980,7 @@ impl InferenceResult { expr_adjustments: Default::default(), coercion_casts: Default::default(), closures_data: Default::default(), + defined_anon_consts: Default::default(), } } @@ -1216,17 +1175,20 @@ enum DerefPatBorrowMode { } /// The inference context contains all information needed during type inference. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct InferenceContext<'body, 'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) owner: ExpressionStoreOwnerId, + pub(crate) owner: InferBodyId, + pub(crate) store_owner: ExpressionStoreOwnerId, + pub(crate) generic_def: GenericDefId, pub(crate) store: &'body ExpressionStore, /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext /// and resolve the path via its methods. This will ensure proper error reporting. pub(crate) resolver: Resolver<'db>, target_features: OnceCell<(TargetFeatures<'db>, TargetFeatureIsSafeInTarget)>, pub(crate) edition: Edition, - pub(crate) generic_def: GenericDefId, + allow_using_generic_params: bool, + generics: OnceCell<Generics<'db>>, pub(crate) table: unify::InferenceTable<'db>, pub(crate) lang_items: &'db LangItems, pub(crate) features: &'db UnstableFeatures, @@ -1261,6 +1223,8 @@ pub(crate) struct InferenceContext<'body, 'db> { diagnostics: Diagnostics, vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>, + + defined_anon_consts: RefCell<ThinVec<AnonConstId>>, } #[derive(Clone, Debug)] @@ -1310,22 +1274,15 @@ fn find_continuable<'a, 'db>( impl<'body, 'db> InferenceContext<'body, 'db> { fn new( db: &'db dyn HirDatabase, - owner: ExpressionStoreOwnerId, + owner: InferBodyId, + store_owner: ExpressionStoreOwnerId, + generic_def: GenericDefId, store: &'body ExpressionStore, resolver: Resolver<'db>, + allow_using_generic_params: bool, ) -> Self { - let trait_env = match owner { - ExpressionStoreOwnerId::Signature(generic_def_id) => { - db.trait_environment(ExpressionStoreOwnerId::from(generic_def_id)) - } - ExpressionStoreOwnerId::Body(def_with_body_id) => { - db.trait_environment(ExpressionStoreOwnerId::Body(def_with_body_id)) - } - ExpressionStoreOwnerId::VariantFields(variant_id) => { - db.trait_environment(ExpressionStoreOwnerId::VariantFields(variant_id)) - } - }; - let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), owner); + let trait_env = db.trait_environment(store_owner); + let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), store_owner); let types = crate::next_solver::default_types(db); InferenceContext { result: InferenceResult::new(types.types.error), @@ -1341,7 +1298,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> { return_coercion: None, db, owner, - generic_def: owner.generic_def(db), + store_owner, + generic_def, + allow_using_generic_params, + generics: OnceCell::new(), store, traits_in_scope: resolver.traits_in_scope(db), resolver, @@ -1352,6 +1312,97 @@ impl<'body, 'db> InferenceContext<'body, 'db> { diagnostics: Diagnostics::default(), vars_emitted_type_must_be_known_for: FxHashSet::default(), deferred_call_resolutions: FxHashMap::default(), + defined_anon_consts: RefCell::new(ThinVec::new()), + } + } + + fn merge(&mut self, other: &InferenceResult) { + let InferenceResult { + method_resolutions, + field_resolutions, + variant_resolutions, + assoc_resolutions, + tuple_field_access_types: _, + type_of_expr, + type_of_pat, + type_of_binding, + type_of_type_placeholder, + type_of_opaque, + has_errors: _, + diagnostics: _, + error_ty: _, + expr_adjustments, + pat_adjustments, + binding_modes, + skipped_ref_pats, + coercion_casts, + closures_data, + nodes_with_type_mismatches, + defined_anon_consts: _, + } = &mut self.result; + merge_hash_maps(method_resolutions, &other.method_resolutions); + merge_hash_maps(variant_resolutions, &other.variant_resolutions); + merge_hash_maps(assoc_resolutions, &other.assoc_resolutions); + field_resolutions.extend(other.field_resolutions.iter().map( + |(&field_expr, &field_resolution)| { + let mut field_resolution = field_resolution; + if let Either::Right(tuple_field) = &mut field_resolution { + let tys = other.tuple_field_access_type(tuple_field.tuple); + tuple_field.tuple = + TupleId(self.tuple_field_accesses_rev.insert_full(tys).0 as u32); + }; + (field_expr, field_resolution) + }, + )); + merge_arena_maps(type_of_expr, &other.type_of_expr); + merge_arena_maps(type_of_pat, &other.type_of_pat); + merge_arena_maps(type_of_binding, &other.type_of_binding); + merge_hash_maps(type_of_type_placeholder, &other.type_of_type_placeholder); + merge_hash_maps(type_of_opaque, &other.type_of_opaque); + merge_hash_maps(expr_adjustments, &other.expr_adjustments); + merge_hash_maps(pat_adjustments, &other.pat_adjustments); + merge_arena_maps(binding_modes, &other.binding_modes); + merge_hash_set(skipped_ref_pats, &other.skipped_ref_pats); + merge_hash_set(coercion_casts, &other.coercion_casts); + merge_hash_maps(closures_data, &other.closures_data); + if let Some(other_nodes_with_type_mismatches) = &other.nodes_with_type_mismatches { + merge_hash_set( + nodes_with_type_mismatches.get_or_insert_default(), + other_nodes_with_type_mismatches, + ); + } + self.defined_anon_consts.borrow_mut().extend(other.defined_anon_consts.iter().copied()); + + fn merge_hash_set<T: Hash + Eq + Clone>(dest: &mut FxHashSet<T>, source: &FxHashSet<T>) { + dest.extend(source.iter().cloned()); + } + + #[cfg_attr(debug_assertions, track_caller)] + fn merge_hash_maps<K: Hash + Eq + Clone, V: Clone + PartialEq>( + dest: &mut FxHashMap<K, V>, + source: &FxHashMap<K, V>, + ) { + if cfg!(debug_assertions) { + for (key, src) in source { + assert!(dest.get(key).is_none_or(|dst| dst == src)); + } + } + + dest.extend(source.iter().map(|(k, v)| (k.clone(), v.clone()))); + } + + #[cfg_attr(debug_assertions, track_caller)] + fn merge_arena_maps<K, V: Clone + PartialEq>( + dest: &mut ArenaMap<la_arena::Idx<K>, V>, + source: &ArenaMap<la_arena::Idx<K>, V>, + ) { + if cfg!(debug_assertions) { + for (key, src) in source.iter() { + assert!(dest.get(key).is_none_or(|dst| dst == src)); + } + } + + dest.extend(source.iter().map(|(k, v)| (k, v.clone()))); } } @@ -1362,7 +1413,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) { let (target_features, target_feature_is_safe) = self.target_features.get_or_init(|| { - let target_features = match self.owner { + let target_features = match self.store_owner { ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => { TargetFeatures::from_fn(self.db, id) } @@ -1398,26 +1449,22 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.result.has_errors = true; } - /// Clones `self` and calls `resolve_all()` on it. - // FIXME: Remove this. - pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult { - let mut ctx = self.clone(); - - ctx.type_inference_fallback(); - - // Comment from rustc: - // Even though coercion casts provide type hints, we check casts after fallback for - // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. - let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks); - for mut cast in cast_checks.into_iter() { - if let Err(diag) = cast.check(&mut ctx) { - ctx.diagnostics.push(diag); + /// Copy the inference of defined anon consts to ourselves, so that we don't need to lookup the defining + /// anon const when looking the type of something. + fn merge_anon_consts(&mut self) { + let mut defined_anon_consts = std::mem::take(&mut *self.defined_anon_consts.borrow_mut()); + defined_anon_consts.retain(|&konst| { + if konst.loc(self.db).owner != self.store_owner { + // This comes from the signature, we don't define it. + return false; } - } - ctx.table.select_obligations_where_possible(); - - ctx.resolve_all() + let const_infer = InferenceResult::of(self.db, konst); + self.merge(const_infer); + true + }); + // Caution, other defined anon consts might have been added by `merge()`! + self.defined_anon_consts.borrow_mut().append(&mut defined_anon_consts); } // FIXME: This function should be private in module. It is currently only used in the consteval, since we need @@ -1458,7 +1505,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> { coercion_casts: _, diagnostics: result_diagnostics, nodes_with_type_mismatches, + defined_anon_consts: result_defined_anon_consts, } = &mut result; + + *result_defined_anon_consts = self.defined_anon_consts.into_inner(); + result_defined_anon_consts.shrink_to_fit(); + let mut resolver = WriteBackCtxt::new(table, diagnostics, vars_emitted_type_must_be_known_for); @@ -1557,6 +1609,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(id.into()), LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container), Span::Dummy, ); @@ -1564,11 +1617,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.return_ty = return_ty; } - fn collect_static(&mut self, data: &StaticSignature) { + fn collect_static(&mut self, id: StaticId, data: &StaticSignature) { let return_ty = self.make_ty( data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(id.into()), LifetimeElisionKind::Elided(self.types.regions.statik), Span::Dummy, ); @@ -1581,6 +1635,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let mut param_tys = self.with_ty_lowering( &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(func.into()), LifetimeElisionKind::for_fn_params(data), |ctx| data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>(), ); @@ -1621,6 +1676,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let return_ty = self.with_ty_lowering( &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(func.into()), LifetimeElisionKind::for_fn_ret(self.interner()), |ctx| { ctx.impl_trait_mode(ImplTraitLoweringMode::Opaque); @@ -1672,10 +1728,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } - pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> { - if c.is_ct_error() { self.table.next_const_var(Span::Dummy) } else { c } - } - fn infer_body(&mut self, body_expr: ExprId) { match self.return_coercion { Some(_) => self.infer_return(body_expr), @@ -1776,6 +1828,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { &mut self, store: &ExpressionStore, types_source: InferenceTyDiagnosticSource, + store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R, ) -> R { @@ -1785,8 +1838,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { store, &self.diagnostics, types_source, + store_owner, self.generic_def, lifetime_elision, + self.allow_using_generic_params, + &self.defined_anon_consts, ); f(&mut ctx) } @@ -1798,6 +1854,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.with_ty_lowering( self.store, InferenceTyDiagnosticSource::Body, + self.store_owner, LifetimeElisionKind::Infer, f, ) @@ -1808,11 +1865,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> { type_ref: TypeRefId, store: &ExpressionStore, type_source: InferenceTyDiagnosticSource, + store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, span: Span, ) -> Ty<'db> { - let ty = self - .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref)); + let ty = self.with_ty_lowering(store, type_source, store_owner, lifetime_elision, |ctx| { + ctx.lower_ty(type_ref) + }); let ty = self.process_user_written_ty(span, ty); // Record the association from placeholders' TypeRefId to type variables. @@ -1839,34 +1898,54 @@ impl<'body, 'db> InferenceContext<'body, 'db> { type_ref, self.store, InferenceTyDiagnosticSource::Body, + self.store_owner, LifetimeElisionKind::Infer, type_ref.into(), ) } - pub(crate) fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Const<'db> { - let const_ = self.with_ty_lowering( - self.store, - InferenceTyDiagnosticSource::Body, - LifetimeElisionKind::Infer, - |ctx| ctx.lower_const(const_ref, ty), - ); - self.insert_type_vars(const_, const_ref.expr.into()) + fn generics(&self) -> &Generics<'db> { + self.generics.get_or_init(|| { + crate::generics::generics(self.db, self.store_owner.generic_def(self.db)) + }) } - pub(crate) fn make_path_as_body_const( + pub(crate) fn create_body_anon_const( &mut self, - type_ref: TypeRefId, - path: &Path, - ty: Ty<'db>, + expr: ExprId, + expected_ty: Ty<'db>, + allow_using_generic_params: bool, ) -> Const<'db> { - let const_ = self.with_ty_lowering( + never!(expected_ty.has_infer(), "cannot have infer vars in an anon const's ty"); + let konst = create_anon_const( + self.interner(), + self.store_owner, self.store, - InferenceTyDiagnosticSource::Body, - LifetimeElisionKind::Infer, - |ctx| ctx.lower_path_as_const(path, ty), + expr, + &self.resolver, + expected_ty, + &|| self.generics(), + Some(self.infcx()), + (!(allow_using_generic_params && self.allow_using_generic_params)).then_some(0), ); - self.insert_type_vars(const_, type_ref.into()) + + if let Ok(konst) = konst + && let ConstKind::Unevaluated(konst) = konst.kind() + && let GeneralConstId::AnonConstId(konst) = konst.def.0 + { + self.defined_anon_consts.borrow_mut().push(konst); + } + + self.write_expr_ty(expr, expected_ty); + // FIXME: Report an error if needed. + konst.unwrap_or_else(|_| self.table.next_const_var(Span::Dummy)) + } + + pub(crate) fn make_path_as_body_const(&mut self, path: &Path) -> Const<'db> { + let forbid_params_after = if self.allow_using_generic_params { None } else { Some(0) }; + // FIXME: Report errors. + path_to_const(self.db, &self.resolver, &|| self.generics(), forbid_params_after, path) + .unwrap_or_else(|_| self.table.next_const_var(Span::Dummy)) } fn err_ty(&self) -> Ty<'db> { @@ -1877,6 +1956,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let lt = self.with_ty_lowering( self.store, InferenceTyDiagnosticSource::Body, + self.store_owner, LifetimeElisionKind::Infer, |ctx| ctx.lower_lifetime(lifetime_ref), ); @@ -2100,8 +2180,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.store, &self.diagnostics, InferenceTyDiagnosticSource::Body, + self.store_owner, self.generic_def, LifetimeElisionKind::Infer, + self.allow_using_generic_params, + &self.defined_anon_consts, ); if let Some(type_anchor) = path.type_anchor() { @@ -2549,7 +2632,7 @@ impl<'db> Expectation<'db> { Expectation::None } - fn resolve(&self, table: &mut unify::InferenceTable<'db>) -> Expectation<'db> { + fn resolve(&self, table: &unify::InferenceTable<'db>) -> Expectation<'db> { match self { Expectation::None => Expectation::None, Expectation::HasType(t) => Expectation::HasType(table.shallow_resolve(*t)), @@ -2560,7 +2643,7 @@ impl<'db> Expectation<'db> { } } - fn to_option(&self, table: &mut unify::InferenceTable<'db>) -> Option<Ty<'db>> { + fn to_option(&self, table: &unify::InferenceTable<'db>) -> Option<Ty<'db>> { match self.resolve(table) { Expectation::None => None, Expectation::HasType(t) |