Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22141 from ChayimFriedman2/more-port
fix: Port and refactor more stuff to match rustc
Shoyu Vanilla (Flint) 4 weeks ago
parent 8703e35 · parent b3b27b4 · commit f0d1d3b
-rw-r--r--crates/hir-def/src/lang_item.rs35
-rw-r--r--crates/hir-def/src/unstable_features.rs1
-rw-r--r--crates/hir-ty/src/dyn_compatibility.rs14
-rw-r--r--crates/hir-ty/src/generics.rs5
-rw-r--r--crates/hir-ty/src/infer.rs62
-rw-r--r--crates/hir-ty/src/infer/cast.rs7
-rw-r--r--crates/hir-ty/src/infer/closure.rs14
-rw-r--r--crates/hir-ty/src/infer/coerce.rs6
-rw-r--r--crates/hir-ty/src/infer/expr.rs419
-rw-r--r--crates/hir-ty/src/infer/opaques.rs2
-rw-r--r--crates/hir-ty/src/infer/path.rs44
-rw-r--r--crates/hir-ty/src/infer/unify.rs182
-rw-r--r--crates/hir-ty/src/lib.rs115
-rw-r--r--crates/hir-ty/src/next_solver/fulfill.rs19
-rw-r--r--crates/hir-ty/src/next_solver/infer/mod.rs18
-rw-r--r--crates/hir-ty/src/next_solver/infer/snapshot/mod.rs6
-rw-r--r--crates/hir-ty/src/next_solver/infer/traits.rs8
-rw-r--r--crates/hir-ty/src/next_solver/ty.rs4
-rw-r--r--crates/hir-ty/src/traits.rs97
-rw-r--r--crates/hir/src/lib.rs18
-rw-r--r--crates/intern/src/symbol/symbols.rs1
21 files changed, 477 insertions, 600 deletions
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 6071ed2981..adc445c2a8 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -7,8 +7,8 @@ use intern::{Symbol, sym};
use stdx::impl_from;
use crate::{
- AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, MacroId,
- ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
+ AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId,
+ ItemContainerId, MacroId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
attrs::AttrFlags,
db::DefDatabase,
nameres::{DefMap, assoc::TraitItems, crate_def_map, crate_local_def_map},
@@ -102,6 +102,8 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
lang_items.fill_non_lang_core_items(db, crate_def_map);
}
+ lang_items.resolve_manually(db);
+
if lang_items.is_empty() { None } else { Some(Box::new(lang_items)) }
}
@@ -190,6 +192,23 @@ fn resolve_core_macro(
current.scope.makro(&Name::new_symbol_root(name))
}
+impl LangItems {
+ fn resolve_manually(&mut self, db: &dyn DefDatabase) {
+ (|| {
+ let into_future_into_future = self.IntoFutureIntoFuture?;
+ let ItemContainerId::TraitId(into_future) = into_future_into_future.loc(db).container
+ else {
+ return None;
+ };
+ self.IntoFuture = Some(into_future);
+ self.IntoFutureOutput = into_future
+ .trait_items(db)
+ .associated_type_by_name(&Name::new_symbol_root(sym::Output));
+ Some(())
+ })();
+ }
+}
+
#[salsa::tracked(returns(as_deref))]
pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Box<[TraitId]>> {
let mut traits = Vec::new();
@@ -221,6 +240,10 @@ macro_rules! language_item_table {
@non_lang_core_macros:
$( core::$($non_lang_macro_module:ident)::*, $non_lang_macro:ident, $non_lang_macro_field:ident; )*
+
+ @resolve_manually:
+
+ $( $resolve_manually:ident, $resolve_manually_type:ident; )*
) => {
#[allow(non_snake_case)] // FIXME: Should we remove this?
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
@@ -235,6 +258,9 @@ macro_rules! language_item_table {
$(
pub $non_lang_macro_field: Option<MacroId>,
)*
+ $(
+ pub $resolve_manually: Option<$resolve_manually_type>,
+ )*
}
impl LangItems {
@@ -247,6 +273,7 @@ macro_rules! language_item_table {
$( self.$lang_item = self.$lang_item.or(other.$lang_item); )*
$( self.$non_lang_trait = self.$non_lang_trait.or(other.$non_lang_trait); )*
$( self.$non_lang_macro_field = self.$non_lang_macro_field.or(other.$non_lang_macro_field); )*
+ $( self.$resolve_manually = self.$resolve_manually.or(other.$resolve_manually); )*
}
fn assign_lang_item(&mut self, name: Symbol, target: LangItemTarget) {
@@ -538,4 +565,8 @@ language_item_table! { LangItems =>
core::marker, CoercePointee, CoercePointeeDerive;
core::marker, Copy, CopyDerive;
core::clone, Clone, CloneDerive;
+
+ @resolve_manually:
+ IntoFuture, TraitId;
+ IntoFutureOutput, TypeAliasId;
}
diff --git a/crates/hir-def/src/unstable_features.rs b/crates/hir-def/src/unstable_features.rs
index 559726fe9b..f581f02617 100644
--- a/crates/hir-def/src/unstable_features.rs
+++ b/crates/hir-def/src/unstable_features.rs
@@ -92,4 +92,5 @@ define_unstable_features! {
ref_pat_eat_one_layer_2024_structural,
deref_patterns,
mut_ref,
+ type_changing_struct_update,
}
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index ee7527446a..0cf7f650f0 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -21,11 +21,14 @@ use crate::{
db::{HirDatabase, InternedOpaqueTyId},
lower::{GenericPredicates, associated_ty_item_bounds},
next_solver::{
- AliasTy, Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, Goal, ParamEnv,
- ParamTy, SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode, infer::DbInternerInferExt,
+ AliasTy, Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, ParamEnv, ParamTy,
+ SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode,
+ infer::{
+ DbInternerInferExt,
+ traits::{Obligation, ObligationCause},
+ },
mk_param,
},
- traits::next_trait_solve_in_ctxt,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -474,12 +477,11 @@ fn receiver_is_dispatchable<'db>(
// Receiver: DispatchFromDyn<Receiver[Self => U]>
let predicate =
TraitRef::new(interner, dispatch_from_dyn_did.into(), [receiver_ty, unsized_receiver_ty]);
- let goal = Goal::new(interner, param_env, predicate);
+ let obligation = Obligation::new(interner, ObligationCause::dummy(), param_env, predicate);
let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
// the receiver is dispatchable iff the obligation holds
- let res = next_trait_solve_in_ctxt(&infcx, goal);
- res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes))
+ infcx.predicate_must_hold_modulo_regions(&obligation)
}
fn receiver_for_self_ty<'db>(
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
index 822942eec3..b041281844 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/crates/hir-ty/src/generics.rs
@@ -131,11 +131,6 @@ impl<'db> Generics<'db> {
self.parent_generics().map_or(0, Generics::len)
}
- /// Returns numbers of generic parameters excluding those from parent.
- pub(crate) fn len_self(&self) -> usize {
- self.params.len()
- }
-
pub(crate) fn len_lifetimes_self(&self) -> usize {
self.params.len_lifetimes()
}
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 54f334b66d..fd0612e066 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -35,8 +35,8 @@ use base_db::{Crate, FxIndexMap};
use either::Either;
use hir_def::{
AdtId, AssocItemId, AttrDefId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId,
- FieldId, FunctionId, GenericDefId, GenericParamId, HasModule, ItemContainerId, LocalFieldId,
- Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId,
+ FieldId, FunctionId, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, TraitId,
+ TupleFieldId, TupleId, TypeOrConstParamId, VariantId,
attrs::AttrFlags,
expr_store::{Body, ExpressionStore, HygieneId, RootExprOrigin, path::Path},
hir::{BindingId, ExprId, ExprOrPatId, LabelId, PatId},
@@ -49,7 +49,6 @@ use hir_def::{
};
use hir_expand::{mod_path::ModPath, name::Name};
use indexmap::IndexSet;
-use intern::sym;
use la_arena::ArenaMap;
use rustc_ast_ir::Mutability;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -83,8 +82,8 @@ use crate::{
},
method_resolution::CandidateId,
next_solver::{
- AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region,
- StoredGenericArgs, StoredTy, StoredTys, Ty, TyKind, Tys,
+ AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArgs,
+ StoredTy, StoredTys, Ty, TyKind, Tys,
abi::Safety,
infer::{InferCtxt, ObligationInspector, traits::ObligationCause},
},
@@ -1240,7 +1239,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
db.trait_environment(ExpressionStoreOwnerId::VariantFields(variant_id))
}
};
- let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner));
+ let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), owner);
let types = crate::next_solver::default_types(db);
InferenceContext {
result: InferenceResult::new(types.types.error),
@@ -1791,10 +1790,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.table.insert_type_vars(ty)
}
- fn unify(&mut self, ty1: Ty<'db>, ty2: Ty<'db>) -> bool {
- self.table.unify(ty1, ty2)
- }
-
/// Attempts to returns the deeply last field of nested structures, but
/// does not apply any normalization in its search. Returns the same type
/// if input `ty` is not a structure at all.
@@ -1871,12 +1866,8 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.table.shallow_resolve(ty)
}
- fn resolve_associated_type(
- &mut self,
- inner_ty: Ty<'db>,
- assoc_ty: Option<TypeAliasId>,
- ) -> Ty<'db> {
- self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
+ pub(crate) fn resolve_vars_if_possible<T: TypeFoldable<DbInterner<'db>>>(&self, t: T) -> T {
+ self.table.resolve_vars_if_possible(t)
}
fn demand_eqtype(
@@ -1974,30 +1965,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
ty.unwrap_or_else(|| self.expr_ty(e))
}
- fn resolve_associated_type_with_params(
- &mut self,
- inner_ty: Ty<'db>,
- assoc_ty: Option<TypeAliasId>,
- // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
- // handled when we support them.
- params: &[GenericArg<'db>],
- ) -> Ty<'db> {
- match assoc_ty {
- Some(res_assoc_ty) => {
- let alias = Ty::new_alias(
- self.interner(),
- AliasTy::new(
- self.interner(),
- AliasTyKind::Projection { def_id: res_assoc_ty.into() },
- iter::once(inner_ty.into()).chain(params.iter().copied()),
- ),
- );
- self.table.try_structurally_resolve_type(alias)
- }
- None => self.err_ty(),
- }
- }
-
fn resolve_variant(
&mut self,
node: ExprOrPatId,
@@ -2323,19 +2290,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
}
- fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
- trait_.trait_items(self.db).associated_type_by_name(&Name::new_symbol_root(sym::Output))
- }
-
- fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
- let ItemContainerId::TraitId(trait_) =
- self.lang_items.IntoFutureIntoFuture?.lookup(self.db).container
- else {
- return None;
- };
- self.resolve_output_on(trait_)
- }
-
fn resolve_boxed_box(&self) -> Option<AdtId> {
let struct_ = self.lang_items.OwnedBox?;
Some(struct_.into())
@@ -2489,7 +2443,7 @@ impl<'db> Expectation<'db> {
fn only_has_type(&self, table: &mut unify::InferenceTable<'db>) -> Option<Ty<'db>> {
match self {
- Expectation::HasType(t) => Some(table.shallow_resolve(*t)),
+ Expectation::HasType(t) => Some(table.resolve_vars_if_possible(*t)),
Expectation::Castable(_) | Expectation::RValueLikeUnsized(_) | Expectation::None => {
None
}
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index 09855766d8..d23a32d81b 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -147,7 +147,8 @@ impl<'db> CastCheck<'db> {
return Ok(());
}
- if !self.cast_ty.has_infer_types() && !ctx.table.is_sized(self.cast_ty) {
+ if !self.cast_ty.has_infer_types() && !ctx.table.type_is_sized_modulo_regions(self.cast_ty)
+ {
return Err(InferenceDiagnostic::CastToUnsized {
expr: self.expr,
cast_ty: self.cast_ty.store(),
@@ -199,7 +200,7 @@ impl<'db> CastCheck<'db> {
// array-ptr-cast
CastTy::Ptr(t, m) => {
let t = ctx.table.try_structurally_resolve_type(t);
- if !ctx.table.is_sized(t) {
+ if !ctx.table.type_is_sized_modulo_regions(t) {
return Err(CastError::IllegalCast);
}
self.check_ref_cast(ctx, inner_ty, mutbl, t, m)
@@ -520,7 +521,7 @@ fn pointer_kind<'db>(
) -> Result<Option<PointerKind<'db>>, ()> {
let ty = ctx.table.try_structurally_resolve_type(ty);
- if ctx.table.is_sized(ty) {
+ if ctx.table.type_is_sized_modulo_regions(ty) {
return Ok(Some(PointerKind::Thin));
}
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 0d2de9b984..a53ab7daaa 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -440,8 +440,7 @@ impl<'db> InferenceContext<'_, 'db> {
.eq(inferred_fnptr_sig, generalized_fnptr_sig)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
- let resolved_sig =
- self.table.infer_ctxt.resolve_vars_if_possible(generalized_fnptr_sig);
+ let resolved_sig = self.resolve_vars_if_possible(generalized_fnptr_sig);
if resolved_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() {
expected_sig = Some(resolved_sig.fn_sig(self.interner()));
@@ -531,7 +530,7 @@ impl<'db> InferenceContext<'_, 'db> {
&self,
projection: PolyProjectionPredicate<'db>,
) -> Option<PolyFnSig<'db>> {
- let projection = self.table.infer_ctxt.resolve_vars_if_possible(projection);
+ let projection = self.resolve_vars_if_possible(projection);
let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1);
debug!(?arg_param_ty);
@@ -576,7 +575,7 @@ impl<'db> InferenceContext<'_, 'db> {
&mut self,
projection: PolyProjectionPredicate<'db>,
) -> Option<PolyFnSig<'db>> {
- let projection = self.table.infer_ctxt.resolve_vars_if_possible(projection);
+ let projection = self.resolve_vars_if_possible(projection);
let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1);
debug!(?arg_param_ty);
@@ -822,11 +821,8 @@ impl<'db> InferenceContext<'_, 'db> {
.eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
all_obligations.extend(obligations);
- let inputs = supplied_sig
- .inputs()
- .iter()
- .copied()
- .map(|ty| table.infer_ctxt.resolve_vars_if_possible(ty));
+ let inputs =
+ supplied_sig.inputs().iter().copied().map(|ty| table.resolve_vars_if_possible(ty));
expected_sigs.liberated_sig = table.interner().mk_fn_sig(
inputs,
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index db912c0eb6..962fc752a5 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -152,10 +152,8 @@ where
let snapshot = self.infcx().start_snapshot();
let result = f(self);
match result {
- Ok(_) => {}
- Err(_) => {
- self.infcx().rollback_to(snapshot);
- }
+ Ok(_) => self.infcx().commit_from(snapshot),
+ Err(_) => self.infcx().rollback_to(snapshot),
}
result
}
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index e84a03a2e7..73d81ad16e 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -4,11 +4,12 @@ use std::{iter::repeat_with, mem};
use either::Either;
use hir_def::{
- FieldId, GenericDefId, ItemContainerId, Lookup, TupleFieldId, TupleId,
+ AdtId, FieldId, TupleFieldId, TupleId, VariantId,
expr_store::path::{GenericArgs as HirGenericArgs, Path},
hir::{
Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId,
- InlineAsmKind, LabelId, Literal, Pat, PatId, RecordSpread, Statement, UnaryOp,
+ InlineAsmKind, LabelId, Literal, Pat, PatId, RecordLitField, RecordSpread, Statement,
+ UnaryOp,
},
resolver::ValueNs,
signatures::VariantFields,
@@ -16,27 +17,27 @@ use hir_def::{
use hir_def::{FunctionId, hir::ClosureKind};
use hir_expand::name::Name;
use rustc_ast_ir::Mutability;
+use rustc_hash::FxHashMap;
use rustc_type_ir::{
InferTy, Interner,
inherent::{AdtDef, GenericArgs as _, IntoKind, Ty as _},
};
+use stdx::never;
use syntax::ast::RangeOp;
use tracing::debug;
use crate::{
Adjust, Adjustment, CallableDefId, Rawness, consteval,
- generics::generics,
infer::{AllowTwoPhase, BreakableKind, coerce::CoerceMany, find_continuable, pat::PatOrigin},
- lower::{GenericPredicates, lower_mutability},
+ lower::lower_mutability,
method_resolution::{self, CandidateId, MethodCallee, MethodError},
next_solver::{
- ClauseKind, FnSig, GenericArg, GenericArgs, TraitRef, Ty, TyKind, TypeError,
+ ClauseKind, FnSig, GenericArg, GenericArgs, Ty, TyKind, TypeError,
infer::{
BoundRegionConversionTime, InferOk,
traits::{Obligation, ObligationCause},
},
obligation_ctxt::ObligationCtxt,
- util::clauses_as_obligations,
},
};
@@ -60,17 +61,41 @@ impl<'db> InferenceContext<'_, 'db> {
) -> Ty<'db> {
let ty = self.infer_expr_inner(tgt_expr, expected, is_read);
if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
- let could_unify = self.unify(ty, expected_ty);
- if !could_unify {
- self.result.type_mismatches.get_or_insert_default().insert(
- tgt_expr.into(),
- TypeMismatch { expected: expected_ty.store(), actual: ty.store() },
- );
- }
+ _ = self.demand_eqtype(tgt_expr.into(), expected_ty, ty);
}
ty
}
+ pub(crate) fn infer_expr_suptype_coerce_never(
+ &mut self,
+ expr: ExprId,
+ expected: &Expectation<'db>,
+ is_read: ExprIsRead,
+ ) -> Ty<'db> {
+ let ty = self.infer_expr_inner(expr, expected, is_read);
+ if ty.is_never() {
+ if let Some(adjustments) = self.result.expr_adjustments.get(&expr) {
+ return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments {
+ target.as_ref()
+ } else {
+ self.err_ty()
+ };
+ }
+
+ if let Some(target) = expected.only_has_type(&mut self.table) {
+ self.coerce(expr, ty, target, AllowTwoPhase::No, ExprIsRead::Yes)
+ .expect("never-to-any coercion should always succeed")
+ } else {
+ ty
+ }
+ } else {
+ if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
+ _ = self.demand_suptype(expr.into(), expected_ty, ty);
+ }
+ ty
+ }
+ }
+
pub(crate) fn infer_expr_no_expect(
&mut self,
tgt_expr: ExprId,
@@ -283,13 +308,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
} else {
if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
- let could_unify = self.unify(ty, expected_ty);
- if !could_unify {
- self.result.type_mismatches.get_or_insert_default().insert(
- expr.into(),
- TypeMismatch { expected: expected_ty.store(), actual: ty.store() },
- );
- }
+ _ = self.demand_eqtype(expr.into(), ty, expected_ty);
}
ty
}
@@ -579,80 +598,10 @@ impl<'db> InferenceContext<'_, 'db> {
self.types.types.never
}
Expr::RecordLit { path, fields, spread, .. } => {
- let (ty, def_id) = self.resolve_variant(tgt_expr.into(), path, false);
-
- if let Some(t) = expected.only_has_type(&mut self.table) {
- self.unify(ty, t);
- }
-
- let substs = ty.as_adt().map(|(_, s)| s).unwrap_or(self.types.empty.generic_args);
- if let Some(variant) = def_id {
- self.write_variant_resolution(tgt_expr.into(), variant);
- }
- match def_id {
- _ if fields.is_empty() => {}
- Some(def) => {
- let field_types = self.db.field_types(def);
- let variant_data = def.fields(self.db);
- let visibilities = VariantFields::field_visibilities(self.db, def);
- for field in fields.iter() {
- let field_def = {
- match variant_data.field(&field.name) {
- Some(local_id) => {
- if !visibilities[local_id]
- .is_visible_from(self.db, self.resolver.module())
- {
- self.push_diagnostic(
- InferenceDiagnostic::NoSuchField {
- field: field.expr.into(),
- private: Some(local_id),
- variant: def,
- },
- );
- }
- Some(local_id)
- }
- None => {
- self.push_diagnostic(InferenceDiagnostic::NoSuchField {
- field: field.expr.into(),
- private: None,
- variant: def,
- });
- None
- }
- }
- };
- let field_ty = field_def.map_or(self.err_ty(), |it| {
- field_types[it].get().instantiate(self.interner(), &substs)
- });
-
- // Field type might have some unknown types
- // FIXME: we may want to emit a single type variable for all instance of type fields?
- let field_ty = self.insert_type_vars(field_ty);
- self.infer_expr_coerce(
- field.expr,
- &Expectation::has_type(field_ty),
- ExprIsRead::Yes,
- );
- }
- }
- None => {
- for field in fields.iter() {
- // Field projections don't constitute reads.
- self.infer_expr_coerce(field.expr, &Expectation::None, ExprIsRead::No);
- }
- }
- }
- if let RecordSpread::Expr(expr) = *spread {
- self.infer_expr_coerce_never(expr, &Expectation::has_type(ty), ExprIsRead::Yes);
- }
- ty
+ self.infer_record_expr(tgt_expr, expected, path, fields, *spread)
}
Expr::Field { expr, name } => self.infer_field_access(tgt_expr, *expr, name, expected),
- Expr::Await { expr } => {
- let inner_ty = self.infer_expr_inner(*expr, &Expectation::none(), ExprIsRead::Yes);
- self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
- }
+ Expr::Await { expr } => self.infer_await_expr(*expr),
Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_body_ty(*type_ref);
let expr_ty =
@@ -1019,6 +968,243 @@ impl<'db> InferenceContext<'_, 'db> {
ty
}
+ fn infer_await_expr(&mut self, awaitee: ExprId) -> Ty<'db> {
+ let awaitee_ty = self.infer_expr_no_expect(awaitee, ExprIsRead::Yes);
+ let (Some(into_future), Some(into_future_output)) =
+ (self.lang_items.IntoFuture, self.lang_items.IntoFutureOutput)
+ else {
+ return self.types.types.error;
+ };
+ self.table.register_bound(awaitee_ty, into_future, ObligationCause::new());
+ // Do not eagerly normalize.
+ Ty::new_projection(self.interner(), into_future_output.into(), [awaitee_ty])
+ }
+
+ fn infer_record_expr(
+ &mut self,
+ expr: ExprId,
+ expected: &Expectation<'db>,
+ path: &Path,
+ fields: &[RecordLitField],
+ base_expr: RecordSpread,
+ ) -> Ty<'db> {
+ // Find the relevant variant
+ let (adt_ty, Some(variant)) = self.resolve_variant(expr.into(), path, false) else {
+ // FIXME: Emit an error.
+ for field in fields {
+ self.infer_expr_no_expect(field.expr, ExprIsRead::Yes);
+ }
+
+ return self.types.types.error;
+ };
+ self.write_variant_resolution(expr.into(), variant);
+
+ // Prohibit struct expressions when non-exhaustive flag is set.
+ if self.has_applicable_non_exhaustive(variant.into()) {
+ // FIXME: Emit an error.
+ }
+
+ self.check_record_expr_fields(adt_ty, expected, expr, variant, fields, base_expr);
+
+ self.require_type_is_sized(adt_ty);
+ adt_ty
+ }
+
+ fn check_record_expr_fields(
+ &mut self,
+ adt_ty: Ty<'db>,
+ expected: &Expectation<'db>,
+ expr: ExprId,
+ variant: VariantId,
+ hir_fields: &[RecordLitField],
+ base_expr: RecordSpread,
+ ) {
+ let interner = self.interner();
+
+ let adt_ty = self.table.try_structurally_resolve_type(adt_ty);
+ let adt_ty_hint = expected.only_has_type(&mut self.table).and_then(|expected| {
+ self.infcx()
+ .fudge_inference_if_ok(|| {
+ let mut ocx = ObligationCtxt::new(self.infcx());
+ ocx.sup(&ObligationCause::new(), self.table.param_env, expected, adt_ty)?;
+ if !ocx.try_evaluate_obligations().is_empty() {
+ return Err(TypeError::Mismatch);
+ }
+ Ok(self.resolve_vars_if_possible(adt_ty))
+ })
+ .ok()
+ });
+ if let Some(adt_ty_hint) = adt_ty_hint {
+ // re-link the variables that the fudging above can create.
+ _ = self.demand_eqtype(expr.into(), adt_ty_hint, adt_ty);
+ }
+
+ let TyKind::Adt(adt, args) = adt_ty.kind() else {
+ never!("non-ADT passed to check_struct_expr_fields");
+ return;
+ };
+ let adt_id = adt.def_id().0;
+
+ let variant_fields = variant.fields(self.db);
+ let variant_field_tys = self.db.field_types(variant);
+ let variant_field_vis = VariantFields::field_visibilities(self.db, variant);
+ let mut remaining_fields = variant_fields
+ .fields()
+ .iter()
+ .map(|(i, field)| (field.name.clone(), i))
+ .collect::<FxHashMap<_, _>>();
+
+ let mut seen_fields = FxHashMap::default();
+
+ // Type-check each field.
+ for field in hir_fields {
+ let name = &field.name;
+ let field_type = if let Some(i) = remaining_fields.remove(name) {
+ seen_fields.insert(name, i);
+
+ if !self.resolver.is_visible(self.db, variant_field_vis[i]) {
+ self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+ field: field.expr.into(),
+ private: Some(i),
+ variant,
+ });
+ }
+
+ variant_field_tys[i].get().instantiate(interner, args)
+ } else {
+ if let Some(field_idx) = seen_fields.get(&name) {
+ // FIXME: Emit an error: duplicate field.
+ variant_field_tys[*field_idx].get().instantiate(interner, args)
+ } else {
+ self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+ field: field.expr.into(),
+ private: None,
+ variant,
+ });
+ self.types.types.error
+ }
+ };
+
+ // Check that the expected field type is WF. Otherwise, we emit no use-site error
+ // in the case of coercions for non-WF fields, which leads to incorrect error
+ // tainting. See issue #126272.
+ self.table.register_wf_obligation(field_type.into(), ObligationCause::new());
+
+ // Make sure to give a type to the field even if there's
+ // an error, so we can continue type-checking.
+ self.infer_expr_coerce(field.expr, &Expectation::has_type(field_type), ExprIsRead::Yes);
+ }
+
+ // Make sure the programmer specified correct number of fields.
+ if matches!(adt_id, AdtId::UnionId(_)) && hir_fields.len() != 1 {
+ // FIXME: Emit an error: unions must specify exactly one field.
+ }
+
+ match base_expr {
+ RecordSpread::FieldDefaults => {
+ let mut missing_mandatory_fields = Vec::new();
+ let mut missing_optional_fields = Vec::new();
+ for (field_idx, field) in variant_fields.fields().iter() {
+ if remaining_fields.remove(&field.name).is_some() {
+ if field.default_value.is_none() {
+ missing_mandatory_fields.push(field_idx);
+ } else {
+ missing_optional_fields.push(field_idx);
+ }
+ }
+ }
+ if !missing_mandatory_fields.is_empty() {
+ // FIXME: Emit an error: missing fields.
+ }
+ }
+ RecordSpread::Expr(base_expr) => {
+ // FIXME: We are currently creating two branches here in order to maintain
+ // consistency. But they should be merged as much as possible.
+ if self.features.type_changing_struct_update {
+ if matches!(adt_id, AdtId::StructId(_)) {
+ // Make some fresh generic parameters for our ADT type.
+ let fresh_args = self.table.fresh_args_for_item(adt_id.into());
+ // We do subtyping on the FRU fields first, so we can
+ // learn exactly what types we expect the base expr
+ // needs constrained to be compatible with the struct
+ // type we expect from the expectation value.
+ for (field_idx, field) in variant_fields.fields().iter() {
+ let fru_ty = variant_field_tys[field_idx]
+ .get()
+ .instantiate(interner, fresh_args);
+ if remaining_fields.remove(&field.name).is_some() {
+ let target_ty =
+ variant_field_tys[field_idx].get().instantiate(interner, args);
+ let cause = ObligationCause::new();
+ match self.table.at(&cause).sup(target_ty, fru_ty) {
+ Ok(InferOk { obligations, value: () }) => {
+ self.table.register_predicates(obligations)
+ }
+ Err(_) => {
+ never!(
+ "subtyping remaining fields of type changing FRU \
+ failed: {target_ty:?} != {fru_ty:?}: {:?}",
+ field.name,
+ );
+ }
+ }
+ }
+ }
+ // The use of fresh args that we have subtyped against
+ // our base ADT type's fields allows us to guide inference
+ // along so that, e.g.
+ // ```
+ // MyStruct<'a, F1, F2, const C: usize> {
+ // f: F1,
+ // // Other fields that reference `'a`, `F2`, and `C`
+ // }
+ //
+ // let x = MyStruct {
+ // f: 1usize,
+ // ..other_struct
+ // };
+ // ```
+ // will have the `other_struct` expression constrained to
+ // `MyStruct<'a, _, F2, C>`, as opposed to just `_`...
+ // This is important to allow coercions to happen in
+ // `other_struct` itself. See `coerce-in-base-expr.rs`.
+ let fresh_base_ty = Ty::new_adt(self.interner(), adt_id, fresh_args);
+ self.infer_expr_suptype_coerce_never(
+ base_expr,
+ &Expectation::has_type(self.resolve_vars_if_possible(fresh_base_ty)),
+ ExprIsRead::Yes,
+ );
+ } else {
+ // Check the base_expr, regardless of a bad expected adt_ty, so we can get
+ // type errors on that expression, too.
+ self.infer_expr_no_expect(base_expr, ExprIsRead::Yes);
+ // FIXME: Emit an error: functional update syntax on non-struct.
+ }
+ } else {
+ self.infer_expr_suptype_coerce_never(
+ base_expr,
+ &Expectation::has_type(adt_ty),
+ ExprIsRead::Yes,
+ );
+ if !matches!(adt_id, AdtId::StructId(_)) {
+ // FIXME: Emit an error: functional update syntax on non-struct.
+ }
+ }
+ }
+ RecordSpread::None => {
+ if !matches!(adt_id, AdtId::UnionId(_))
+ && !remaining_fields.is_empty()
+ //~ non_exhaustive already reported, which will only happen for extern modules
+ && !self.has_applicable_non_exhaustive(adt_id.into())
+ {
+ debug!(?remaining_fields);
+
+ // FIXME: Emit an error: missing fields.
+ }
+ }
+ }
+ }
+
fn demand_scrutinee_type(
&mut self,
scrut: ExprId,
@@ -1255,7 +1441,7 @@ impl<'db> InferenceContext<'_, 'db> {
// NB: this should *not* coerce.
// tail calls don't support any coercions except lifetimes ones (like `&'static u8 -> &'a u8`).
- self.unify(call_expr_ty, ret_ty);
+ _ = self.demand_eqtype(expr.into(), call_expr_ty, ret_ty);
}
None => {
// FIXME: diagnose `become` outside of functions
@@ -1553,7 +1739,7 @@ impl<'db> InferenceContext<'_, 'db> {
MethodCallee { def_id, args, sig }
}
- fn check_call(
+ fn infer_method_call_as_call(
&mut self,
tgt_expr: ExprId,
args: &[ExprId],
@@ -1564,7 +1750,14 @@ impl<'db> InferenceContext<'_, 'db> {
is_varargs: bool,
expected: &Expectation<'db>,
) -> Ty<'db> {
- self.register_obligations_for_call(callee_ty);
+ if let TyKind::FnDef(def_id, args) = callee_ty.kind() {
+ let def_id = match def_id.0 {
+ CallableDefId::FunctionId(it) => it.into(),
+ CallableDefId::StructId(it) => it.into(),
+ CallableDefId::EnumVariantId(it) => it.loc(self.db).parent.into(),
+ };
+ self.add_required_obligations_for_value_path(def_id, args);
+ }
self.check_call_arguments(
tgt_expr,
@@ -1670,7 +1863,7 @@ impl<'db> InferenceContext<'_, 'db> {
}),
};
match recovered {
- Some((callee_ty, sig, strip_first)) => self.check_call(
+ Some((callee_ty, sig, strip_first)) => self.infer_method_call_as_call(
tgt_expr,
args,
callee_ty,
@@ -1958,40 +2151,6 @@ impl<'db> InferenceContext<'_, 'db> {
if !args_count_matches {}
}
- fn register_obligations_for_call(&mut self, callable_ty: Ty<'db>) {
- let callable_ty = self.table.try_structurally_resolve_type(callable_ty);
- if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind() {
- let generic_predicates = GenericPredicates::query_all(
- self.db,
- GenericDefId::from_callable(self.db, fn_def.0),
- );
- let param_env = self.table.param_env;
- self.table.register_predicates(clauses_as_obligations(
- generic_predicates.iter_instantiated(self.interner(), parameters.as_slice()),
- ObligationCause::new(),
- param_env,
- ));
- // add obligation for trait implementation, if this is a trait method
- match fn_def.0 {
- CallableDefId::FunctionId(f) => {
- if let ItemContainerId::TraitId(trait_) = f.lookup(self.db).container {
- // construct a TraitRef
- let trait_params_len = generics(self.db, trait_.into()).len();
- let substs =
- GenericArgs::new_from_slice(&parameters.as_slice()[..trait_params_len]);
- self.table.register_predicate(Obligation::new(
- self.interner(),
- ObligationCause::new(),
- self.table.param_env,
- TraitRef::new_from_args(self.interner(), trait_.into(), substs),
- ));
- }
- }
- CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
- }
- }
- }
-
pub(super) fn with_breakable_ctx<T>(
&mut self,
kind: BreakableKind,
diff --git a/crates/hir-ty/src/infer/opaques.rs b/crates/hir-ty/src/infer/opaques.rs
index a39288721b..02bce22d6d 100644
--- a/crates/hir-ty/src/infer/opaques.rs
+++ b/crates/hir-ty/src/infer/opaques.rs
@@ -68,7 +68,7 @@ impl<'db> InferenceContext<'_, 'db> {
mut opaque_types: Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)>,
) {
for entry in opaque_types.iter_mut() {
- *entry = self.table.infer_ctxt.resolve_vars_if_possible(*entry);
+ *entry = self.resolve_vars_if_possible(*entry);
}
debug!(?opaque_types);
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 835721942a..0687d56024 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -12,13 +12,11 @@ use stdx::never;
use crate::{
InferenceDiagnostic, ValueTyDefId,
- generics::generics,
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
lower::{GenericPredicates, LifetimeElisionKind},
method_resolution::{self, CandidateId, MethodError},
next_solver::{
- GenericArg, GenericArgs, TraitRef, Ty,
- infer::traits::{Obligation, ObligationCause},
+ GenericArg, GenericArgs, TraitRef, Ty, infer::traits::ObligationCause,
util::clauses_as_obligations,
},
};
@@ -226,7 +224,7 @@ impl<'db> InferenceContext<'_, 'db> {
}
}
- fn add_required_obligations_for_value_path(
+ pub(super) fn add_required_obligations_for_value_path(
&mut self,
def: GenericDefId,
subst: GenericArgs<'db>,
@@ -239,25 +237,6 @@ impl<'db> InferenceContext<'_, 'db> {
ObligationCause::new(),
param_env,
));
-
- // We need to add `Self: Trait` obligation when `def` is a trait assoc item.
- let container = match def {
- GenericDefId::FunctionId(id) => id.lookup(self.db).container,
- GenericDefId::ConstId(id) => id.lookup(self.db).container,
- _ => return,
- };
-
- if let ItemContainerId::TraitId(trait_) = container {
- let parent_len = generics(self.db, def).parent_generics().map_or(0, |g| g.len_self());
- let parent_subst = GenericArgs::new_from_slice(&subst.as_slice()[..parent_len]);
- let trait_ref = TraitRef::new_from_args(interner, trait_.into(), parent_subst);
- self.table.register_predicate(Obligation::new(
- interner,
- ObligationCause::new(),
- param_env,
- trait_ref,
- ));
- }
}
fn resolve_trait_assoc_item(
@@ -334,25 +313,14 @@ impl<'db> InferenceContext<'_, 'db> {
let impl_substs = self.table.fresh_args_for_item(impl_id.into());
let impl_self_ty =
self.db.impl_self_ty(impl_id).instantiate(self.interner(), impl_substs);
- self.unify(impl_self_ty, ty);
+ _ = self.demand_eqtype(id, impl_self_ty, ty);
impl_substs
}
ItemContainerId::TraitId(trait_) => {
// we're picking this method
- let args = GenericArgs::fill_rest(
- self.interner(),
- trait_.into(),
- [ty.into()],
- |_, id, _| self.table.next_var_for_param(id),
- );
- let trait_ref = TraitRef::new_from_args(self.interner(), trait_.into(), args);
- self.table.register_predicate(Obligation::new(
- self.interner(),
- ObligationCause::new(),
- self.table.param_env,
- trait_ref,
- ));
- args
+ GenericArgs::fill_rest(self.interner(), trait_.into(), [ty.into()], |_, id, _| {
+ self.table.next_var_for_param(id)
+ })
}
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
never!("assoc item contained in module/extern block");
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index b0f916b8c0..c28fea0ff1 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -3,10 +3,10 @@
use std::fmt;
use base_db::Crate;
-use hir_def::{AdtId, ExpressionStoreOwnerId, GenericParamId, TraitId};
+use hir_def::{ExpressionStoreOwnerId, GenericParamId, TraitId};
use rustc_hash::FxHashSet;
use rustc_type_ir::{
- TyVid, TypeFoldable, TypeVisitableExt, UpcastFrom,
+ TyVid, TypeFoldable, TypeVisitableExt,
inherent::{Const as _, GenericArg as _, IntoKind, Ty as _},
solve::Certainty,
};
@@ -15,23 +15,20 @@ use smallvec::SmallVec;
use crate::{
db::HirDatabase,
next_solver::{
- Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Goal,
+ Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, TyKind,
TypingMode,
fulfill::{FulfillmentCtxt, NextSolverError},
infer::{
- DbInternerInferExt, InferCtxt, InferOk, InferResult,
- at::{At, ToTrace},
+ DbInternerInferExt, InferCtxt, InferOk,
+ at::At,
snapshot::CombinedSnapshot,
traits::{Obligation, ObligationCause, PredicateObligation},
},
inspect::{InspectConfig, InspectGoal, ProofTreeVisitor},
obligation_ctxt::ObligationCtxt,
},
- traits::{
- NextTraitSolveResult, ParamEnvAndCrate, next_trait_solve_canonical_in_ctxt,
- next_trait_solve_in_ctxt,
- },
+ traits::ParamEnvAndCrate,
};
struct NestedObligationsForSelfTy<'a, 'db> {
@@ -133,11 +130,6 @@ pub(crate) struct InferenceTable<'db> {
pub(super) diverging_type_vars: FxHashSet<Ty<'db>>,
}
-pub(crate) struct InferenceTableSnapshot<'db> {
- ctxt_snapshot: CombinedSnapshot,
- obligations: FulfillmentCtxt<'db>,
-}
-
impl<'db> InferenceTable<'db> {
/// Inside hir-ty you should use this for inference only, and always pass `owner`.
/// Outside it, always pass `owner = None`.
@@ -145,14 +137,10 @@ impl<'db> InferenceTable<'db> {
db: &'db dyn HirDatabase,
trait_env: ParamEnv<'db>,
krate: Crate,
- owner: Option<ExpressionStoreOwnerId>,
+ owner: ExpressionStoreOwnerId,
) -> Self {
let interner = DbInterner::new_with(db, krate);
- let typing_mode = match owner {
- Some(owner) => TypingMode::typeck_for_body(interner, owner.into()),
- // IDE things wants to reveal opaque types.
- None => TypingMode::PostAnalysis,
- };
+ let typing_mode = TypingMode::typeck_for_body(interner, owner.into());
let infer_ctxt = interner.infer_ctxt().build(typing_mode);
InferenceTable {
db,
@@ -172,6 +160,10 @@ impl<'db> InferenceTable<'db> {
self.infer_ctxt.type_is_copy_modulo_regions(self.param_env, ty)
}
+ pub(crate) fn type_is_sized_modulo_regions(&self, ty: Ty<'db>) -> bool {
+ self.infer_ctxt.type_is_sized_modulo_regions(self.param_env, ty)
+ }
+
pub(crate) fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'db>) -> bool {
self.infer_ctxt.type_is_use_cloned_modulo_regions(self.param_env, ty)
}
@@ -253,23 +245,6 @@ impl<'db> InferenceTable<'db> {
self.diverging_type_vars.insert(ty);
}
- pub(crate) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'db>, T>
- where
- T: TypeFoldable<DbInterner<'db>>,
- {
- // try to resolve obligations before canonicalizing, since this might
- // result in new knowledge about variables
- self.select_obligations_where_possible();
- self.infer_ctxt.canonicalize_response(t)
- }
-
- pub(crate) fn normalize_alias_ty(&mut self, alias: Ty<'db>) -> Ty<'db> {
- self.infer_ctxt
- .at(&ObligationCause::new(), self.param_env)
- .structurally_normalize_ty(alias, &mut self.fulfillment_cx)
- .unwrap_or(alias)
- }
-
pub(crate) fn next_ty_var(&self) -> Ty<'db> {
self.infer_ctxt.next_ty_var()
}
@@ -313,17 +288,6 @@ impl<'db> InferenceTable<'db> {
value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals))
}
- /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
- pub(crate) fn unify<T: ToTrace<'db>>(&mut self, ty1: T, ty2: T) -> bool {
- self.try_unify(ty1, ty2).map(|infer_ok| self.register_infer_ok(infer_ok)).is_ok()
- }
-
- /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
- /// caller needs to deal with them.
- pub(crate) fn try_unify<T: ToTrace<'db>>(&mut self, t1: T, t2: T) -> InferResult<'db, ()> {
- self.at(&ObligationCause::new()).eq(t1, t2)
- }
-
pub(crate) fn at<'a>(&'a self, cause: &'a ObligationCause) -> At<'a, 'db> {
self.infer_ctxt.at(cause, self.param_env)
}
@@ -332,6 +296,10 @@ impl<'db> InferenceTable<'db> {
self.infer_ctxt.shallow_resolve(ty)
}
+ pub(crate) fn resolve_vars_if_possible<T: TypeFoldable<DbInterner<'db>>>(&self, t: T) -> T {
+ self.infer_ctxt.resolve_vars_if_possible(t)
+ }
+
pub(crate) fn resolve_vars_with_obligations<T>(&mut self, t: T) -> T
where
T: rustc_type_ir::TypeFoldable<DbInterner<'db>>,
@@ -380,16 +348,13 @@ impl<'db> InferenceTable<'db> {
// FIXME: Err if it still contain infer vars.
}
- pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'db> {
- let ctxt_snapshot = self.infer_ctxt.start_snapshot();
- let obligations = self.fulfillment_cx.clone();
- InferenceTableSnapshot { ctxt_snapshot, obligations }
+ pub(crate) fn snapshot(&mut self) -> CombinedSnapshot {
+ self.infer_ctxt.start_snapshot()
}
#[tracing::instrument(skip_all)]
- pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'db>) {
- self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot);
- self.fulfillment_cx = snapshot.obligations;
+ pub(crate) fn rollback_to(&mut self, snapshot: CombinedSnapshot) {
+ self.infer_ctxt.rollback_to(snapshot);
}
pub(crate) fn commit_if_ok<T, E>(
@@ -399,51 +364,12 @@ impl<'db> InferenceTable<'db> {
let snapshot = self.snapshot();
let result = f(self);
match result {
- Ok(_) => {}
- Err(_) => {
- self.rollback_to(snapshot);
- }
+ Ok(_) => self.infer_ctxt.commit_from(snapshot),
+ Err(_) => self.rollback_to(snapshot),
}
result
}
- /// Checks an obligation without registering it. Useful mostly to check
- /// whether a trait *might* be implemented before deciding to 'lock in' the
- /// choice (during e.g. method resolution or deref).
- #[tracing::instrument(level = "debug", skip(self))]
- pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult {
- let goal = Goal { param_env: self.param_env, predicate };
- let canonicalized = self.canonicalize(goal);
-
- next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized)
- }
-
- pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) {
- let goal = Goal { param_env: self.param_env, predicate };
- self.register_obligation_in_env(goal)
- }
-
- #[tracing::instrument(level = "debug", skip(self))]
- fn register_obligation_in_env(&mut self, goal: Goal<'db, Predicate<'db>>) {
- let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal);
- tracing::debug!(?result);
- match result {
- Ok((_, Certainty::Yes)) => {}
- Err(rustc_type_ir::solve::NoSolution) => {}
- Ok((_, Certainty::Maybe { .. })) => {
- self.fulfillment_cx.register_predicate_obligation(
- &self.infer_ctxt,
- Obligation::new(
- self.interner(),
- ObligationCause::new(),
- goal.param_env,
- goal.predicate,
- ),
- );
- }
- }
- }
-
pub(crate) fn register_bound(&mut self, ty: Ty<'db>, def_id: TraitId, cause: ObligationCause) {
if !ty.references_non_lt_error() {
let trait_ref = TraitRef::new(self.interner(), def_id.into(), [ty]);
@@ -533,70 +459,6 @@ impl<'db> InferenceTable<'db> {
pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> {
if c.is_ct_error() { self.next_const_var() } else { c }
}
-
- /// Check if given type is `Sized` or not
- pub(crate) fn is_sized(&mut self, ty: Ty<'db>) -> bool {
- fn short_circuit_trivial_tys(ty: Ty<'_>) -> Option<bool> {
- match ty.kind() {
- TyKind::Bool
- | TyKind::Char
- | TyKind::Int(_)
- | TyKind::Uint(_)
- | TyKind::Float(_)
- | TyKind::Ref(..)
- | TyKind::RawPtr(..)
- | TyKind::Never
- | TyKind::FnDef(..)
- | TyKind::Array(..)
- | TyKind::FnPtr(..) => Some(true),
- TyKind::Slice(..) | TyKind::Str | TyKind::Dynamic(..) => Some(false),
- _ => None,
- }
- }
-
- let mut ty = ty;
- ty = self.try_structurally_resolve_type(ty);
- if let Some(sized) = short_circuit_trivial_tys(ty) {
- return sized;
- }
-
- {
- let mut structs = SmallVec::<[_; 8]>::new();
- // Must use a loop here and not recursion because otherwise users will conduct completely
- // artificial examples of structs that have themselves as the tail field and complain r-a crashes.
- while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
- let struct_data = id.fields(self.db);
- if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
- let last_field_ty = self.db.field_types(id.into())[last_field]
- .get()
- .instantiate(self.interner(), subst);
- if structs.contains(&ty) {
- // A struct recursively contains itself as a tail field somewhere.
- return true; // Don't overload the users with too many errors.
- }
- structs.push(ty);
- // Structs can have DST as its last field and such cases are not handled
- // as unsized by the chalk, so we do this manually.
- ty = last_field_ty;
- ty = self.try_structurally_resolve_type(ty);
- if let Some(sized) = short_circuit_trivial_tys(ty) {
- return sized;
- }
- } else {
- break;
- };
- }
- }
-
- let Some(sized) = self.interner().lang_items().Sized else {
- return false;
- };
- let sized_pred = Predicate::upcast_from(
- TraitRef::new(self.interner(), sized.into(), [ty]),
- self.interner(),
- );
- self.try_obligation(sized_pred).certain()
- }
}
impl fmt::Debug for InferenceTable<'_> {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index c6c7856c8c..2973b970f3 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -71,7 +71,7 @@ use macros::GenericTypeVisitable;
use mir::{MirEvalError, VTableMap};
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use rustc_type_ir::{
- BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, UpcastFrom,
+ BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt,
inherent::{IntoKind, Ty as _},
};
use syntax::ast::{ConstArg, make};
@@ -80,12 +80,17 @@ use traits::FnTrait;
use crate::{
db::HirDatabase,
display::{DisplayTarget, HirDisplay},
- infer::unify::InferenceTable,
lower::SupertraitsInfo,
next_solver::{
AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical,
- CanonicalVarKind, CanonicalVarKinds, ClauseKind, Const, ConstKind, DbInterner, FnSig,
- GenericArgs, PolyFnSig, Predicate, Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi,
+ CanonicalVarKind, CanonicalVarKinds, ClauseKind, Const, ConstKind, DbInterner, GenericArgs,
+ PolyFnSig, Region, RegionKind, TraitRef, Ty, TyKind, TypingMode,
+ abi::Safety,
+ infer::{
+ DbInternerInferExt,
+ traits::{Obligation, ObligationCause},
+ },
+ obligation_ctxt::ObligationCtxt,
},
};
@@ -525,68 +530,64 @@ pub fn associated_type_shorthand_candidates(
/// To be used from `hir` only.
pub fn callable_sig_from_fn_trait<'db>(
self_ty: Ty<'db>,
- trait_env: ParamEnvAndCrate<'db>,
+ param_env: ParamEnvAndCrate<'db>,
db: &'db dyn HirDatabase,
) -> Option<(FnTrait, PolyFnSig<'db>)> {
- let mut table = InferenceTable::new(db, trait_env.param_env, trait_env.krate, None);
- let lang_items = table.interner().lang_items();
+ let ParamEnvAndCrate { param_env, krate } = param_env;
+ let interner = DbInterner::new_with(db, krate);
+ let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
+ let lang_items = interner.lang_items();
+ let cause = ObligationCause::dummy();
+
+ let impls_trait = |trait_: FnTrait| {
+ let mut ocx = ObligationCtxt::new(&infcx);
+ let tupled_args = infcx.next_ty_var();
+ let args = GenericArgs::new_from_slice(&[self_ty.into(), tupled_args.into()]);
+ let trait_id = trait_.get_id(lang_items)?;
+ let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args);
+ let obligation = Obligation::new(interner, cause.clone(), param_env, trait_ref);
+ ocx.register_obligation(obligation);
+ if !ocx.try_evaluate_obligations().is_empty() {
+ return None;
+ }
+ let tupled_args =
+ infcx.resolve_vars_if_possible(tupled_args).replace_infer_with_error(interner);
+ if tupled_args.is_tuple() { Some(tupled_args) } else { None }
+ };
- let fn_once_trait = FnTrait::FnOnce.get_id(lang_items)?;
+ let (trait_, args) = 'find_trait: {
+ for trait_ in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
+ if let Some(args) = impls_trait(trait_) {
+ break 'find_trait (trait_, args);
+ }
+ }
+ return None;
+ };
+
+ let fn_once_trait = lang_items.FnOnce?;
let output_assoc_type = fn_once_trait
.trait_items(db)
.associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
-
- // Register two obligations:
- // - Self: FnOnce<?args_ty>
- // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
- let args_ty = table.next_ty_var();
- let args = GenericArgs::new_from_slice(&[self_ty.into(), args_ty.into()]);
- let trait_ref = TraitRef::new_from_args(table.interner(), fn_once_trait.into(), args);
- let projection = Ty::new_alias(
- table.interner(),
- AliasTy::new_from_args(
- table.interner(),
+ let output_projection = Ty::new_alias(
+ interner,
+ AliasTy::new(
+ interner,
rustc_type_ir::Projection { def_id: output_assoc_type.into() },
- args,
+ [self_ty, args],
),
);
-
- let pred = Predicate::upcast_from(trait_ref, table.interner());
- if !table.try_obligation(pred).no_solution() {
- table.register_obligation(pred);
- let return_ty = table.normalize_alias_ty(projection);
- for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
- let fn_x_trait = fn_x.get_id(lang_items)?;
- let trait_ref = TraitRef::new_from_args(table.interner(), fn_x_trait.into(), args);
- if !table
- .try_obligation(Predicate::upcast_from(trait_ref, table.interner()))
- .no_solution()
- {
- let ret_ty = table.resolve_completely(return_ty);
- let args_ty = table.resolve_completely(args_ty);
- let TyKind::Tuple(params) = args_ty.kind() else {
- return None;
- };
- let inputs_and_output = Tys::new_from_iter(
- table.interner(),
- params.iter().chain(std::iter::once(ret_ty)),
- );
-
- return Some((
- fn_x,
- Binder::dummy(FnSig {
- inputs_and_output,
- c_variadic: false,
- safety: abi::Safety::Safe,
- abi: FnAbi::RustCall,
- }),
- ));
- }
- }
- unreachable!("It should at least implement FnOnce at this point");
- } else {
- None
- }
+ let mut ocx = ObligationCtxt::new(&infcx);
+ let ret = ocx.structurally_normalize_ty(&cause, param_env, output_projection).ok()?;
+ let ret = ret.replace_infer_with_error(interner);
+
+ let sig = Binder::dummy(interner.mk_fn_sig(
+ args.tuple_fields(),
+ ret,
+ false,
+ Safety::Safe,
+ FnAbi::Rust,
+ ));
+ Some((trait_, sig))
}
struct ParamCollector {
diff --git a/crates/hir-ty/src/next_solver/fulfill.rs b/crates/hir-ty/src/next_solver/fulfill.rs
index 6739795a00..cd0cb59760 100644
--- a/crates/hir-ty/src/next_solver/fulfill.rs
+++ b/crates/hir-ty/src/next_solver/fulfill.rs
@@ -44,7 +44,6 @@ pub struct FulfillmentCtxt<'db> {
/// outside of this snapshot leads to subtle bugs if the snapshot
/// gets rolled back. Because of this we explicitly check that we only
/// use the context in exactly this snapshot.
- #[expect(unused)]
usable_in_snapshot: usize,
try_evaluate_obligations_scratch: PendingObligations<'db>,
}
@@ -120,24 +119,22 @@ impl<'db> FulfillmentCtxt<'db> {
}
impl<'db> FulfillmentCtxt<'db> {
- #[tracing::instrument(level = "trace", skip(self, _infcx))]
+ #[tracing::instrument(level = "trace", skip(self, infcx))]
pub(crate) fn register_predicate_obligation(
&mut self,
- _infcx: &InferCtxt<'db>,
+ infcx: &InferCtxt<'db>,
obligation: PredicateObligation<'db>,
) {
- // FIXME: See the comment in `try_evaluate_obligations()`.
- // assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
+ assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
self.obligations.register(obligation, None);
}
pub(crate) fn register_predicate_obligations(
&mut self,
- _infcx: &InferCtxt<'db>,
+ infcx: &InferCtxt<'db>,
obligations: impl IntoIterator<Item = PredicateObligation<'db>>,
) {
- // FIXME: See the comment in `try_evaluate_obligations()`.
- // assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
+ assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
obligations.into_iter().for_each(|obligation| self.obligations.register(obligation, None));
}
@@ -157,11 +154,7 @@ impl<'db> FulfillmentCtxt<'db> {
&mut self,
infcx: &InferCtxt<'db>,
) -> Vec<NextSolverError<'db>> {
- // FIXME(next-solver): We should bring this assertion back. Currently it panics because
- // there are places which use `InferenceTable` and open a snapshot and register obligations
- // and select. They should use a different `ObligationCtxt` instead. Then we'll be also able
- // to not put the obligations queue in `InferenceTable`'s snapshots.
- // assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
+ assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
self.try_evaluate_obligations_scratch.clear();
let mut errors = Vec::new();
loop {
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index de21c5442b..1eacc295c9 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -58,7 +58,7 @@ pub mod relate;
pub mod resolve;
pub mod select;
pub(crate) mod snapshot;
-pub(crate) mod traits;
+pub mod traits;
mod type_variable;
mod unify_key;
@@ -494,8 +494,7 @@ impl<'db> InferCtxt<'db> {
/// check::<&'_ T>();
/// }
/// ```
- #[expect(dead_code, reason = "this is used in rustc")]
- fn predicate_must_hold_considering_regions(
+ pub fn predicate_must_hold_considering_regions(
&self,
obligation: &PredicateObligation<'db>,
) -> bool {
@@ -507,8 +506,10 @@ impl<'db> InferCtxt<'db> {
/// not entirely accurate if inference variables are involved.
///
/// This version ignores all outlives constraints.
- #[expect(dead_code, reason = "this is used in rustc")]
- fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'db>) -> bool {
+ pub fn predicate_must_hold_modulo_regions(
+ &self,
+ obligation: &PredicateObligation<'db>,
+ ) -> bool {
self.evaluate_obligation(obligation).must_apply_modulo_regions()
}
@@ -610,6 +611,13 @@ impl<'db> InferCtxt<'db> {
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
}
+ pub fn type_is_sized_modulo_regions(&self, param_env: ParamEnv<'db>, ty: Ty<'db>) -> bool {
+ let Some(sized_def_id) = self.interner.lang_items().Sized else {
+ return true;
+ };
+ traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, sized_def_id)
+ }
+
pub fn type_is_use_cloned_modulo_regions(&self, param_env: ParamEnv<'db>, ty: Ty<'db>) -> bool {
let ty = self.resolve_vars_if_possible(ty);
diff --git a/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs b/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs
index 705aa43fb1..39c8a37adb 100644
--- a/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/snapshot/mod.rs
@@ -47,7 +47,7 @@ impl<'db> InferCtxt<'db> {
UndoLogs::<UndoLog<'db>>::num_open_snapshots(&self.inner.borrow_mut().undo_log)
}
- pub(crate) fn start_snapshot(&self) -> CombinedSnapshot {
+ pub fn start_snapshot(&self) -> CombinedSnapshot {
debug!("start_snapshot()");
let mut inner = self.inner.borrow_mut();
@@ -60,7 +60,7 @@ impl<'db> InferCtxt<'db> {
}
#[instrument(skip(self, snapshot), level = "debug")]
- pub(crate) fn rollback_to(&self, snapshot: CombinedSnapshot) {
+ pub fn rollback_to(&self, snapshot: CombinedSnapshot) {
let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot;
self.universe.set(universe);
@@ -71,7 +71,7 @@ impl<'db> InferCtxt<'db> {
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn commit_from(&self, snapshot: CombinedSnapshot) {
+ pub fn commit_from(&self, snapshot: CombinedSnapshot) {
let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, universe: _ } =
snapshot;
diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs
index dde6234836..5b875d2960 100644
--- a/crates/hir-ty/src/next_solver/infer/traits.rs
+++ b/crates/hir-ty/src/next_solver/infer/traits.rs
@@ -185,12 +185,12 @@ impl<'db> PredicateObligation<'db> {
impl<'db, O> Obligation<'db, O> {
pub fn new(
- tcx: DbInterner<'db>,
+ interner: DbInterner<'db>,
cause: ObligationCause,
param_env: ParamEnv<'db>,
predicate: impl Upcast<DbInterner<'db>, O>,
) -> Obligation<'db, O> {
- Self::with_depth(tcx, cause, 0, param_env, predicate)
+ Self::with_depth(interner, cause, 0, param_env, predicate)
}
/// We often create nested obligations without setting the correct depth.
@@ -202,13 +202,13 @@ impl<'db, O> Obligation<'db, O> {
}
pub fn with_depth(
- tcx: DbInterner<'db>,
+ interner: DbInterner<'db>,
cause: ObligationCause,
recursion_depth: usize,
param_env: ParamEnv<'db>,
predicate: impl Upcast<DbInterner<'db>, O>,
) -> Obligation<'db, O> {
- let predicate = predicate.upcast(tcx);
+ let predicate = predicate.upcast(interner);
Obligation { cause, param_env, recursion_depth, predicate }
}
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index c953e79602..0fd02eb8ca 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -626,6 +626,10 @@ impl<'db> Ty<'db> {
}
}
+ pub fn is_tuple(self) -> bool {
+ matches!(self.kind(), TyKind::Tuple(_))
+ }
+
pub fn as_tuple(self) -> Option<Tys<'db>> {
match self.kind() {
TyKind::Tuple(tys) => Some(tys),
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 878696c721..0dc834ddcc 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -15,18 +15,15 @@ use hir_def::{
};
use hir_expand::name::Name;
use intern::sym;
-use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt};
use rustc_type_ir::{
TypingMode,
- inherent::{AdtDef, BoundExistentialPredicates, IntoKind, Span as _},
- solve::Certainty,
+ inherent::{AdtDef, BoundExistentialPredicates, IntoKind},
};
use crate::{
db::HirDatabase,
next_solver::{
- Canonical, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, SolverContext, Span,
- StoredClauses, Ty, TyKind,
+ DbInterner, GenericArgs, ParamEnv, StoredClauses, Ty, TyKind,
infer::{
DbInternerInferExt, InferCtxt,
traits::{Obligation, ObligationCause},
@@ -79,91 +76,6 @@ pub fn structurally_normalize_ty<'db>(
ty.replace_infer_with_error(infcx.interner)
}
-#[derive(Clone, Debug, PartialEq)]
-pub enum NextTraitSolveResult {
- Certain,
- Uncertain,
- NoSolution,
-}
-
-impl NextTraitSolveResult {
- pub fn no_solution(&self) -> bool {
- matches!(self, NextTraitSolveResult::NoSolution)
- }
-
- pub fn certain(&self) -> bool {
- matches!(self, NextTraitSolveResult::Certain)
- }
-
- pub fn uncertain(&self) -> bool {
- matches!(self, NextTraitSolveResult::Uncertain)
- }
-}
-
-pub fn next_trait_solve_canonical_in_ctxt<'db>(
- infer_ctxt: &InferCtxt<'db>,
- goal: Canonical<'db, Goal<'db, Predicate<'db>>>,
-) -> NextTraitSolveResult {
- infer_ctxt.probe(|_| {
- let context = <&SolverContext<'db>>::from(infer_ctxt);
-
- tracing::info!(?goal);
-
- let (goal, var_values) = context.instantiate_canonical(&goal);
- tracing::info!(?var_values);
-
- let res = context.evaluate_root_goal(goal, Span::dummy(), None);
-
- let obligation = Obligation {
- cause: ObligationCause::dummy(),
- param_env: goal.param_env,
- recursion_depth: 0,
- predicate: goal.predicate,
- };
- infer_ctxt.inspect_evaluated_obligation(&obligation, &res, || {
- Some(context.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1)
- });
-
- let res = res.map(|r| (r.has_changed, r.certainty));
-
- tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
-
- match res {
- Err(_) => NextTraitSolveResult::NoSolution,
- Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain,
- Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain,
- }
- })
-}
-
-/// Solve a trait goal using next trait solver.
-pub fn next_trait_solve_in_ctxt<'db, 'a>(
- infer_ctxt: &'a InferCtxt<'db>,
- goal: Goal<'db, Predicate<'db>>,
-) -> Result<(HasChanged, Certainty), rustc_type_ir::solve::NoSolution> {
- tracing::info!(?goal);
-
- let context = <&SolverContext<'db>>::from(infer_ctxt);
-
- let res = context.evaluate_root_goal(goal, Span::dummy(), None);
-
- let obligation = Obligation {
- cause: ObligationCause::dummy(),
- param_env: goal.param_env,
- recursion_depth: 0,
- predicate: goal.predicate,
- };
- infer_ctxt.inspect_evaluated_obligation(&obligation, &res, || {
- Some(context.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1)
- });
-
- let res = res.map(|r| (r.has_changed, r.certainty));
-
- tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
-
- res
-}
-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Update)]
pub enum FnTrait {
// Warning: Order is important. If something implements `x` it should also implement
@@ -235,10 +147,9 @@ fn implements_trait_unique_impl<'db>(
let args = create_args(&infcx);
let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args);
- let goal = Goal::new(interner, env.param_env, trait_ref);
- let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal);
- matches!(result, Ok((_, Certainty::Yes)))
+ let obligation = Obligation::new(interner, ObligationCause::dummy(), env.param_env, trait_ref);
+ infcx.predicate_must_hold_modulo_regions(&obligation)
}
pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id: ImplId) -> bool {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index ecd11fb5d7..11598f2a10 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -6561,21 +6561,13 @@ impl<'db> TypeNs<'db> {
);
let trait_ref =
hir_ty::next_solver::TraitRef::new_from_args(infcx.interner, trait_.id.into(), args);
-
- let pred_kind = rustc_type_ir::Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Trait(rustc_type_ir::TraitPredicate {
- trait_ref,
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- }),
- ));
- let predicate = hir_ty::next_solver::Predicate::new(infcx.interner, pred_kind);
- let goal = hir_ty::next_solver::Goal::new(
+ let obligation = hir_ty::next_solver::infer::traits::Obligation::new(
infcx.interner,
- hir_ty::next_solver::ParamEnv::empty(),
- predicate,
+ hir_ty::next_solver::infer::traits::ObligationCause::dummy(),
+ self.env.param_env,
+ trait_ref,
);
- let res = hir_ty::traits::next_trait_solve_in_ctxt(&infcx, goal);
- res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes))
+ infcx.predicate_must_hold_modulo_regions(&obligation)
}
pub fn is_bool(&self) -> bool {
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 8dcc73d81f..25c2e3f733 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -583,4 +583,5 @@ define_symbols! {
ref_pat_eat_one_layer_2024_structural,
deref_patterns,
mut_ref,
+ type_changing_struct_update,
}