Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/expr.rs')
-rw-r--r--crates/hir-ty/src/infer/expr.rs1856
1 files changed, 700 insertions, 1156 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index c5a51dfc4c..01508b0f9b 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -2,54 +2,47 @@
use std::{iter::repeat_with, mem};
-use chalk_ir::{DebruijnIndex, Mutability, TyVariableKind, cast::Cast};
use either::Either;
-use hir_def::hir::ClosureKind;
use hir_def::{
- BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
- expr_store::path::{GenericArg, GenericArgs, Path},
+ BlockId, FieldId, GenericDefId, ItemContainerId, Lookup, TupleFieldId, TupleId,
+ expr_store::path::{GenericArgs as HirGenericArgs, Path},
hir::{
- ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, Expr, ExprId, ExprOrPatId, LabelId,
- Literal, Pat, PatId, Statement, UnaryOp, generics::GenericParamDataRef,
+ Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId,
+ LabelId, Literal, Pat, PatId, Statement, UnaryOp,
},
- lang_item::{LangItem, LangItemTarget},
resolver::ValueNs,
};
+use hir_def::{FunctionId, hir::ClosureKind};
use hir_expand::name::Name;
-use intern::sym;
-use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _};
-use stdx::always;
+use rustc_ast_ir::Mutability;
+use rustc_type_ir::{
+ CoroutineArgs, CoroutineArgsParts, InferTy, Interner,
+ inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _},
+};
use syntax::ast::RangeOp;
use tracing::debug;
-use crate::autoderef::overloaded_deref_ty;
-use crate::next_solver::ErrorGuaranteed;
-use crate::next_solver::infer::DefineOpaqueTypes;
-use crate::next_solver::obligation_ctxt::ObligationCtxt;
use crate::{
- Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext,
- DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar,
- Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval,
+ Adjust, Adjustment, CallableDefId, DeclContext, DeclOrigin, Rawness, TraitEnvironment,
+ autoderef::InferenceContextAutoderef,
+ consteval,
+ db::InternedCoroutine,
generics::generics,
infer::{
- AllowTwoPhase, BreakableKind,
- coerce::{CoerceMany, CoerceNever},
- find_continuable,
+ AllowTwoPhase, BreakableKind, coerce::CoerceMany, find_continuable,
pat::contains_explicit_ref_binding,
},
- lang_items::lang_items_for_bin_op,
- lower::{
- ParamLoweringMode, lower_to_chalk_mutability,
- path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings},
- },
- mapping::{ToChalk, from_chalk},
- method_resolution::{self, VisibleFromModule},
+ lower::{GenericPredicates, lower_mutability},
+ method_resolution::{self, CandidateId, MethodCallee, MethodError},
next_solver::{
- infer::traits::ObligationCause,
- mapping::{ChalkToNextSolver, NextSolverToChalk},
+ ErrorGuaranteed, FnSig, GenericArgs, TraitRef, Ty, TyKind, TypeError,
+ infer::{
+ BoundRegionConversionTime, InferOk,
+ traits::{Obligation, ObligationCause},
+ },
+ obligation_ctxt::ObligationCtxt,
+ util::clauses_as_obligations,
},
- primitive::{self, UintTy},
- static_lifetime, to_chalk_trait_id,
traits::FnTrait,
};
@@ -64,27 +57,31 @@ pub(crate) enum ExprIsRead {
No,
}
-impl<'db> InferenceContext<'db> {
+impl<'db> InferenceContext<'_, 'db> {
pub(crate) fn infer_expr(
&mut self,
tgt_expr: ExprId,
- expected: &Expectation,
+ expected: &Expectation<'db>,
is_read: ExprIsRead,
- ) -> Ty {
+ ) -> 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);
+ let could_unify = self.unify(ty, expected_ty);
if !could_unify {
- self.result.type_mismatches.insert(
- tgt_expr.into(),
- TypeMismatch { expected: expected_ty, actual: ty.clone() },
- );
+ self.result
+ .type_mismatches
+ .get_or_insert_default()
+ .insert(tgt_expr.into(), TypeMismatch { expected: expected_ty, actual: ty });
}
}
ty
}
- pub(crate) fn infer_expr_no_expect(&mut self, tgt_expr: ExprId, is_read: ExprIsRead) -> Ty {
+ pub(crate) fn infer_expr_no_expect(
+ &mut self,
+ tgt_expr: ExprId,
+ is_read: ExprIsRead,
+ ) -> Ty<'db> {
self.infer_expr_inner(tgt_expr, &Expectation::None, is_read)
}
@@ -93,29 +90,18 @@ impl<'db> InferenceContext<'db> {
pub(super) fn infer_expr_coerce(
&mut self,
expr: ExprId,
- expected: &Expectation,
+ expected: &Expectation<'db>,
is_read: ExprIsRead,
- ) -> Ty {
+ ) -> Ty<'db> {
let ty = self.infer_expr_inner(expr, expected, is_read);
if let Some(target) = expected.only_has_type(&mut self.table) {
- let coerce_never = if self.expr_guaranteed_to_constitute_read_for_never(expr, is_read) {
- CoerceNever::Yes
- } else {
- CoerceNever::No
- };
- match self.coerce(
- expr.into(),
- ty.to_nextsolver(self.table.interner),
- target.to_nextsolver(self.table.interner),
- AllowTwoPhase::No,
- coerce_never,
- ) {
- Ok(res) => res.to_chalk(self.table.interner),
+ match self.coerce(expr.into(), ty, target, AllowTwoPhase::No, is_read) {
+ Ok(res) => res,
Err(_) => {
- self.result.type_mismatches.insert(
- expr.into(),
- TypeMismatch { expected: target.clone(), actual: ty.clone() },
- );
+ self.result
+ .type_mismatches
+ .get_or_insert_default()
+ .insert(expr.into(), TypeMismatch { expected: target, actual: ty });
target
}
}
@@ -205,6 +191,23 @@ impl<'db> InferenceContext<'db> {
}
}
+ /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
+ /// yes whether it contains mutable or just immutables ones.
+ //
+ // FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
+ // ref bindings are be implicit after #42640 (default match binding modes). See issue #44848.
+ fn contains_explicit_ref_binding(&self, pat: PatId) -> bool {
+ if let Pat::Bind { id, .. } = self.body[pat]
+ && matches!(self.body[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut)
+ {
+ return true;
+ }
+
+ let mut result = false;
+ self.body.walk_pats_shallow(pat, |pat| result |= self.contains_explicit_ref_binding(pat));
+ result
+ }
+
fn is_syntactic_place_expr(&self, expr: ExprId) -> bool {
match &self.body[expr] {
// Lang item paths cannot currently be local variables or statics.
@@ -252,45 +255,47 @@ impl<'db> InferenceContext<'db> {
}
}
+ #[expect(clippy::needless_return)]
+ pub(crate) fn check_lhs_assignable(&self, lhs: ExprId) {
+ if self.is_syntactic_place_expr(lhs) {
+ return;
+ }
+
+ // FIXME: Emit diagnostic.
+ }
+
fn infer_expr_coerce_never(
&mut self,
expr: ExprId,
- expected: &Expectation,
+ expected: &Expectation<'db>,
is_read: ExprIsRead,
- ) -> Ty {
+ ) -> Ty<'db> {
let ty = self.infer_expr_inner(expr, expected, is_read);
// While we don't allow *arbitrary* coercions here, we *do* allow
// coercions from `!` to `expected`.
if ty.is_never() {
if let Some(adjustments) = self.result.expr_adjustments.get(&expr) {
return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments {
- target.clone()
+ *target
} else {
self.err_ty()
};
}
if let Some(target) = expected.only_has_type(&mut self.table) {
- self.coerce(
- expr.into(),
- ty.to_nextsolver(self.table.interner),
- target.to_nextsolver(self.table.interner),
- AllowTwoPhase::No,
- CoerceNever::Yes,
- )
- .expect("never-to-any coercion should always succeed")
- .to_chalk(self.table.interner)
+ self.coerce(expr.into(), 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) {
- let could_unify = self.unify(&ty, &expected_ty);
+ let could_unify = self.unify(ty, expected_ty);
if !could_unify {
- self.result.type_mismatches.insert(
- expr.into(),
- TypeMismatch { expected: expected_ty, actual: ty.clone() },
- );
+ self.result
+ .type_mismatches
+ .get_or_insert_default()
+ .insert(expr.into(), TypeMismatch { expected: expected_ty, actual: ty });
}
}
ty
@@ -301,9 +306,9 @@ impl<'db> InferenceContext<'db> {
fn infer_expr_inner(
&mut self,
tgt_expr: ExprId,
- expected: &Expectation,
+ expected: &Expectation<'db>,
is_read: ExprIsRead,
- ) -> Ty {
+ ) -> Ty<'db> {
self.db.unwind_if_revision_cancelled();
let expr = &self.body[tgt_expr];
@@ -314,7 +319,7 @@ impl<'db> InferenceContext<'db> {
let expected = &expected.adjust_for_branches(&mut self.table);
self.infer_expr_coerce_never(
condition,
- &Expectation::HasType(self.result.standard_types.bool_.clone()),
+ &Expectation::HasType(self.types.bool),
ExprIsRead::Yes,
);
@@ -327,17 +332,10 @@ impl<'db> InferenceContext<'db> {
coercion_sites[1] = else_branch;
}
let mut coerce = CoerceMany::with_coercion_sites(
- expected
- .coercion_target_type(&mut self.table)
- .to_nextsolver(self.table.interner),
+ expected.coercion_target_type(&mut self.table),
&coercion_sites,
);
- coerce.coerce(
- self,
- &ObligationCause::new(),
- then_branch,
- then_ty.to_nextsolver(self.table.interner),
- );
+ coerce.coerce(self, &ObligationCause::new(), then_branch, then_ty, ExprIsRead::Yes);
match else_branch {
Some(else_branch) => {
let else_ty = self.infer_expr_inner(else_branch, expected, ExprIsRead::Yes);
@@ -346,17 +344,24 @@ impl<'db> InferenceContext<'db> {
self,
&ObligationCause::new(),
else_branch,
- else_ty.to_nextsolver(self.table.interner),
+ else_ty,
+ ExprIsRead::Yes,
);
self.diverges = condition_diverges | then_diverges & else_diverges;
}
None => {
- coerce.coerce_forced_unit(self, tgt_expr, &ObligationCause::new(), true);
+ coerce.coerce_forced_unit(
+ self,
+ tgt_expr,
+ &ObligationCause::new(),
+ true,
+ ExprIsRead::Yes,
+ );
self.diverges = condition_diverges;
}
}
- coerce.complete(self).to_chalk(self.table.interner)
+ coerce.complete(self)
}
&Expr::Let { pat, expr } => {
let child_is_read = if self.pat_guaranteed_to_constitute_read_for_never(pat) {
@@ -367,10 +372,10 @@ impl<'db> InferenceContext<'db> {
let input_ty = self.infer_expr(expr, &Expectation::none(), child_is_read);
self.infer_top_pat(
pat,
- &input_ty,
+ input_ty,
Some(DeclContext { origin: DeclOrigin::LetExpr }),
);
- self.result.standard_types.bool_.clone()
+ self.types.bool
}
Expr::Block { statements, tail, label, id } => {
self.infer_block(tgt_expr, *id, statements, *tail, *label, expected)
@@ -390,12 +395,12 @@ impl<'db> InferenceContext<'db> {
&Expr::Loop { body, label } => {
// FIXME: should be:
// let ty = expected.coercion_target_type(&mut self.table);
- let ty = self.table.new_type_var();
+ let ty = self.table.next_ty_var();
let (breaks, ()) =
self.with_breakable_ctx(BreakableKind::Loop, Some(ty), label, |this| {
this.infer_expr(
body,
- &Expectation::HasType(TyBuilder::unit()),
+ &Expectation::HasType(this.types.unit),
ExprIsRead::Yes,
);
});
@@ -405,7 +410,7 @@ impl<'db> InferenceContext<'db> {
self.diverges = Diverges::Maybe;
breaks
}
- None => self.result.standard_types.never.clone(),
+ None => self.types.never,
}
}
Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => self
@@ -429,41 +434,46 @@ impl<'db> InferenceContext<'db> {
expected,
),
Expr::Match { expr, arms } => {
- let scrutinee_is_read = arms
- .iter()
- .all(|arm| self.pat_guaranteed_to_constitute_read_for_never(arm.pat));
+ let mut scrutinee_is_read = true;
+ let mut contains_ref_bindings = false;
+ for arm in arms {
+ scrutinee_is_read &= self.pat_guaranteed_to_constitute_read_for_never(arm.pat);
+ contains_ref_bindings |= self.contains_explicit_ref_binding(arm.pat);
+ }
let scrutinee_is_read =
if scrutinee_is_read { ExprIsRead::Yes } else { ExprIsRead::No };
- let input_ty = self.infer_expr(*expr, &Expectation::none(), scrutinee_is_read);
+ let input_ty = self.demand_scrutinee_type(
+ *expr,
+ contains_ref_bindings,
+ arms.is_empty(),
+ scrutinee_is_read,
+ );
if arms.is_empty() {
self.diverges = Diverges::Always;
- self.result.standard_types.never.clone()
+ self.types.never
} else {
let matchee_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let mut all_arms_diverge = Diverges::Always;
for arm in arms.iter() {
- let input_ty = self.table.structurally_resolve_type(&input_ty);
- self.infer_top_pat(arm.pat, &input_ty, None);
+ self.infer_top_pat(arm.pat, input_ty, None);
}
let expected = expected.adjust_for_branches(&mut self.table);
let result_ty = match &expected {
// We don't coerce to `()` so that if the match expression is a
// statement it's branches can have any consistent type.
- Expectation::HasType(ty) if *ty != self.result.standard_types.unit => {
- ty.clone()
- }
- _ => self.table.new_type_var(),
+ Expectation::HasType(ty) if *ty != self.types.unit => *ty,
+ _ => self.table.next_ty_var(),
};
- let mut coerce = CoerceMany::new(result_ty.to_nextsolver(self.table.interner));
+ let mut coerce = CoerceMany::new(result_ty);
for arm in arms.iter() {
if let Some(guard_expr) = arm.guard {
self.diverges = Diverges::Maybe;
self.infer_expr_coerce_never(
guard_expr,
- &Expectation::HasType(self.result.standard_types.bool_.clone()),
+ &Expectation::HasType(self.types.bool),
ExprIsRead::Yes,
);
}
@@ -475,13 +485,14 @@ impl<'db> InferenceContext<'db> {
self,
&ObligationCause::new(),
arm.expr,
- arm_ty.to_nextsolver(self.table.interner),
+ arm_ty,
+ ExprIsRead::Yes,
);
}
self.diverges = matchee_diverges | all_arms_diverge;
- coerce.complete(self).to_chalk(self.table.interner)
+ coerce.complete(self)
}
}
Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr),
@@ -493,13 +504,13 @@ impl<'db> InferenceContext<'db> {
bad_value_break: false,
});
};
- self.result.standard_types.never.clone()
+ self.types.never
}
&Expr::Break { expr, label } => {
let val_ty = if let Some(expr) = expr {
let opt_coerce_to = match find_breakable(&mut self.breakables, label) {
Some(ctxt) => match &ctxt.coerce {
- Some(coerce) => coerce.expected_ty().to_chalk(self.table.interner),
+ Some(coerce) => coerce.expected_ty(),
None => {
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
expr: tgt_expr,
@@ -517,7 +528,7 @@ impl<'db> InferenceContext<'db> {
ExprIsRead::Yes,
)
} else {
- TyBuilder::unit()
+ self.types.unit
};
match find_breakable(&mut self.breakables, label) {
@@ -527,7 +538,8 @@ impl<'db> InferenceContext<'db> {
self,
&ObligationCause::new(),
expr.unwrap_or(tgt_expr),
- val_ty.to_nextsolver(self.table.interner),
+ val_ty,
+ ExprIsRead::Yes,
);
// Avoiding borrowck
@@ -546,12 +558,12 @@ impl<'db> InferenceContext<'db> {
});
}
}
- self.result.standard_types.never.clone()
+ self.types.never
}
&Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr),
&Expr::Become { expr } => self.infer_expr_become(expr),
Expr::Yield { expr } => {
- if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
+ if let Some((resume_ty, yield_ty)) = self.resume_yield_tys {
if let Some(expr) = expr {
self.infer_expr_coerce(
*expr,
@@ -559,38 +571,35 @@ impl<'db> InferenceContext<'db> {
ExprIsRead::Yes,
);
} else {
- let unit = self.result.standard_types.unit.clone();
+ let unit = self.types.unit;
let _ = self.coerce(
tgt_expr.into(),
- unit.to_nextsolver(self.table.interner),
- yield_ty.to_nextsolver(self.table.interner),
+ unit,
+ yield_ty,
AllowTwoPhase::No,
- CoerceNever::Yes,
+ ExprIsRead::Yes,
);
}
resume_ty
} else {
// FIXME: report error (yield expr in non-coroutine)
- self.result.standard_types.unknown.clone()
+ self.types.error
}
}
Expr::Yeet { expr } => {
if let &Some(expr) = expr {
self.infer_expr_no_expect(expr, ExprIsRead::Yes);
}
- self.result.standard_types.never.clone()
+ self.types.never
}
Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(tgt_expr.into(), path.as_deref(), false);
if let Some(t) = expected.only_has_type(&mut self.table) {
- self.unify(&ty, &t);
+ self.unify(ty, t);
}
- let substs = ty
- .as_adt()
- .map(|(_, s)| s.clone())
- .unwrap_or_else(|| Substitution::empty(Interner));
+ let substs = ty.as_adt().map(|(_, s)| s).unwrap_or(self.types.empty_args);
if let Some(variant) = def_id {
self.write_variant_resolution(tgt_expr.into(), variant);
}
@@ -628,7 +637,7 @@ impl<'db> InferenceContext<'db> {
}
};
let field_ty = field_def.map_or(self.err_ty(), |it| {
- field_types[it].clone().substitute(Interner, &substs)
+ field_types[it].instantiate(self.interner(), &substs)
});
// Field type might have some unknown types
@@ -649,7 +658,7 @@ impl<'db> InferenceContext<'db> {
}
}
if let Some(expr) = spread {
- self.infer_expr(*expr, &Expectation::has_type(ty.clone()), ExprIsRead::Yes);
+ self.infer_expr(*expr, &Expectation::has_type(ty), ExprIsRead::Yes);
}
ty
}
@@ -660,21 +669,13 @@ impl<'db> InferenceContext<'db> {
}
Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_body_ty(*type_ref);
- let expr_ty = self.infer_expr(
- *expr,
- &Expectation::Castable(cast_ty.clone()),
- ExprIsRead::Yes,
- );
- self.deferred_cast_checks.push(CastCheck::new(
- tgt_expr,
- *expr,
- expr_ty,
- cast_ty.clone(),
- ));
+ let expr_ty =
+ self.infer_expr(*expr, &Expectation::Castable(cast_ty), ExprIsRead::Yes);
+ self.deferred_cast_checks.push(CastCheck::new(tgt_expr, *expr, expr_ty, cast_ty));
cast_ty
}
Expr::Ref { expr, rawness, mutability } => {
- let mutability = lower_to_chalk_mutability(*mutability);
+ let mutability = lower_mutability(*mutability);
let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected
.only_has_type(&mut self.table)
.as_ref()
@@ -688,104 +689,27 @@ impl<'db> InferenceContext<'db> {
// FIXME: record type error - expected reference but found ptr,
// which cannot be coerced
}
- Expectation::rvalue_hint(self, Ty::clone(exp_inner))
+ Expectation::rvalue_hint(self, exp_inner)
} else {
Expectation::none()
};
let inner_ty = self.infer_expr_inner(*expr, &expectation, ExprIsRead::Yes);
match rawness {
- Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
+ Rawness::RawPtr => Ty::new_ptr(self.interner(), inner_ty, mutability),
Rawness::Ref => {
- let lt = self.table.new_lifetime_var();
- TyKind::Ref(mutability, lt, inner_ty)
+ let lt = self.table.next_region_var();
+ Ty::new_ref(self.interner(), lt, inner_ty, mutability)
}
}
- .intern(Interner)
}
&Expr::Box { expr } => self.infer_expr_box(expr, expected),
- Expr::UnaryOp { expr, op } => {
- let inner_ty = self.infer_expr_inner(*expr, &Expectation::none(), ExprIsRead::Yes);
- let inner_ty = self.table.structurally_resolve_type(&inner_ty);
- // FIXME: Note down method resolution her
- match op {
- UnaryOp::Deref => {
- if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref)
- && let Some(deref_fn) = deref_trait
- .trait_items(self.db)
- .method_by_name(&Name::new_symbol_root(sym::deref))
- {
- // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
- // the mutability is not wrong, and will be fixed in `self.infer_mut`).
- self.write_method_resolution(
- tgt_expr,
- deref_fn,
- Substitution::empty(Interner),
- );
- }
- if let Some(derefed) =
- inner_ty.to_nextsolver(self.table.interner).builtin_deref(self.db, true)
- {
- self.table
- .structurally_resolve_type(&derefed.to_chalk(self.table.interner))
- } else {
- let infer_ok = overloaded_deref_ty(
- &self.table,
- inner_ty.to_nextsolver(self.table.interner),
- );
- match infer_ok {
- Some(infer_ok) => self
- .table
- .register_infer_ok(infer_ok)
- .to_chalk(self.table.interner),
- None => self.err_ty(),
- }
- }
- }
- UnaryOp::Neg => {
- match inner_ty.kind(Interner) {
- // Fast path for builtins
- TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_))
- | TyKind::InferenceVar(
- _,
- TyVariableKind::Integer | TyVariableKind::Float,
- ) => inner_ty,
- // Otherwise we resolve via the std::ops::Neg trait
- _ => self
- .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
- }
- }
- UnaryOp::Not => {
- match inner_ty.kind(Interner) {
- // Fast path for builtins
- TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_))
- | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty,
- // Otherwise we resolve via the std::ops::Not trait
- _ => self
- .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
- }
- }
- }
- }
+ Expr::UnaryOp { expr, op } => self.infer_unop_expr(*op, *expr, expected, tgt_expr),
Expr::BinaryOp { lhs, rhs, op } => match op {
- Some(BinaryOp::LogicOp(_)) => {
- let bool_ty = self.result.standard_types.bool_.clone();
- self.infer_expr_coerce(
- *lhs,
- &Expectation::HasType(bool_ty.clone()),
- ExprIsRead::Yes,
- );
- let lhs_diverges = self.diverges;
- self.infer_expr_coerce(
- *rhs,
- &Expectation::HasType(bool_ty.clone()),
- ExprIsRead::Yes,
- );
- // Depending on the LHS' value, the RHS can never execute.
- self.diverges = lhs_diverges;
- bool_ty
+ Some(BinaryOp::Assignment { op: Some(op) }) => {
+ self.infer_assign_op_expr(tgt_expr, *op, *lhs, *rhs)
}
- Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
- _ => self.err_ty(),
+ Some(op) => self.infer_binop_expr(tgt_expr, *op, *lhs, *rhs),
+ None => self.err_ty(),
},
&Expr::Assignment { target, value } => {
// In ordinary (non-destructuring) assignments, the type of
@@ -826,14 +750,14 @@ impl<'db> InferenceContext<'db> {
let is_destructuring_assignment = lhs_ty.is_none();
if let Some(lhs_ty) = lhs_ty {
- self.write_pat_ty(target, lhs_ty.clone());
+ self.write_pat_ty(target, lhs_ty);
self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::No);
} else {
let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes);
let resolver_guard =
self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr);
self.inside_assignment = true;
- self.infer_top_pat(target, &rhs_ty, None);
+ self.infer_top_pat(target, rhs_ty, None);
self.inside_assignment = false;
self.resolver.reset_to_guard(resolver_guard);
}
@@ -844,127 +768,101 @@ impl<'db> InferenceContext<'db> {
// assignments into blocks.
self.table.new_maybe_never_var()
} else {
- self.result.standard_types.unit.clone()
+ self.types.unit
}
}
Expr::Range { lhs, rhs, range_type } => {
let lhs_ty =
lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes));
- let rhs_expect = lhs_ty
- .as_ref()
- .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone()));
+ let rhs_expect = lhs_ty.map_or_else(Expectation::none, Expectation::has_type);
let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect, ExprIsRead::Yes));
+ let single_arg_adt = |adt, ty: Ty<'db>| {
+ Ty::new_adt(
+ self.interner(),
+ adt,
+ GenericArgs::new_from_iter(self.interner(), [ty.into()]),
+ )
+ };
match (range_type, lhs_ty, rhs_ty) {
(RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
- Some(adt) => TyBuilder::adt(self.db, adt).build(),
+ Some(adt) => Ty::new_adt(self.interner(), adt, self.types.empty_args),
None => self.err_ty(),
},
(RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
- Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
+ Some(adt) => single_arg_adt(adt, ty),
None => self.err_ty(),
},
(RangeOp::Inclusive, None, Some(ty)) => {
match self.resolve_range_to_inclusive() {
- Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
+ Some(adt) => single_arg_adt(adt, ty),
None => self.err_ty(),
}
}
(RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
- Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
+ Some(adt) => single_arg_adt(adt, ty),
None => self.err_ty(),
},
(RangeOp::Inclusive, Some(_), Some(ty)) => {
match self.resolve_range_inclusive() {
- Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
+ Some(adt) => single_arg_adt(adt, ty),
None => self.err_ty(),
}
}
(RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
- Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
+ Some(adt) => single_arg_adt(adt, ty),
None => self.err_ty(),
},
(RangeOp::Inclusive, _, None) => self.err_ty(),
}
}
Expr::Index { base, index } => {
- let base_ty = self.infer_expr_inner(*base, &Expectation::none(), ExprIsRead::Yes);
- let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes);
-
- if let Some(index_trait) = self.resolve_lang_trait(LangItem::Index) {
- let canonicalized =
- self.canonicalize(base_ty.clone().to_nextsolver(self.table.interner));
- let receiver_adjustments = method_resolution::resolve_indexing_op(
- &mut self.table,
- canonicalized,
- index_trait,
- );
- let (self_ty, mut adj) = receiver_adjustments
- .map_or((self.err_ty(), Vec::new()), |adj| {
- adj.apply(&mut self.table, base_ty)
- });
-
- // mutability will be fixed up in `InferenceContext::infer_mut`;
- adj.push(Adjustment::borrow(
- Mutability::Not,
- self_ty.clone(),
- self.table.new_lifetime_var(),
- ));
- self.write_expr_adj(*base, adj.into_boxed_slice());
- if let Some(func) = index_trait
- .trait_items(self.db)
- .method_by_name(&Name::new_symbol_root(sym::index))
- {
- let subst = TyBuilder::subst_for_def(self.db, index_trait, None);
- if subst.remaining() != 2 {
- return self.err_ty();
- }
- let subst = subst.push(self_ty.clone()).push(index_ty.clone()).build();
- self.write_method_resolution(tgt_expr, func, subst);
+ let base_t = self.infer_expr_no_expect(*base, ExprIsRead::Yes);
+ let idx_t = self.infer_expr_no_expect(*index, ExprIsRead::Yes);
+
+ let base_t = self.table.structurally_resolve_type(base_t);
+ match self.lookup_indexing(tgt_expr, *base, base_t, idx_t) {
+ Some((trait_index_ty, trait_element_ty)) => {
+ // two-phase not needed because index_ty is never mutable
+ self.demand_coerce(
+ *index,
+ idx_t,
+ trait_index_ty,
+ AllowTwoPhase::No,
+ ExprIsRead::Yes,
+ );
+ self.table.select_obligations_where_possible();
+ trait_element_ty
}
- let assoc = self.resolve_ops_index_output();
- self.resolve_associated_type_with_params(
- self_ty,
- assoc,
- &[index_ty.cast(Interner)],
- )
- } else {
- self.err_ty()
+ // FIXME: Report an error.
+ None => self.types.error,
}
}
Expr::Tuple { exprs, .. } => {
let mut tys = match expected
.only_has_type(&mut self.table)
- .as_ref()
- .map(|t| t.kind(Interner))
+ .map(|t| self.table.try_structurally_resolve_type(t).kind())
{
- Some(TyKind::Tuple(_, substs)) => substs
- .iter(Interner)
- .map(|a| a.assert_ty_ref(Interner).clone())
- .chain(repeat_with(|| self.table.new_type_var()))
+ Some(TyKind::Tuple(substs)) => substs
+ .iter()
+ .chain(repeat_with(|| self.table.next_ty_var()))
.take(exprs.len())
.collect::<Vec<_>>(),
- _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(),
+ _ => (0..exprs.len()).map(|_| self.table.next_ty_var()).collect(),
};
for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
- *ty = self.infer_expr_coerce(
- *expr,
- &Expectation::has_type(ty.clone()),
- ExprIsRead::Yes,
- );
+ *ty =
+ self.infer_expr_coerce(*expr, &Expectation::has_type(*ty), ExprIsRead::Yes);
}
- TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
+ Ty::new_tup(self.interner(), &tys)
}
Expr::Array(array) => self.infer_expr_array(array, expected),
Expr::Literal(lit) => match lit {
- Literal::Bool(..) => self.result.standard_types.bool_.clone(),
- Literal::String(..) => {
- TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
- .intern(Interner)
- }
+ Literal::Bool(..) => self.types.bool,
+ Literal::String(..) => self.types.static_str_ref,
Literal::ByteString(bs) => {
- let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
+ let byte_type = self.types.u8;
let len = consteval::usize_const(
self.db,
@@ -972,75 +870,76 @@ impl<'db> InferenceContext<'db> {
self.resolver.krate(),
);
- let array_type = TyKind::Array(byte_type, len).intern(Interner);
- TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
+ let array_type = Ty::new_array_with_const_len(self.interner(), byte_type, len);
+ Ty::new_ref(self.interner(), self.types.re_static, array_type, Mutability::Not)
}
- Literal::CString(..) => TyKind::Ref(
+ Literal::CString(..) => Ty::new_ref(
+ self.interner(),
+ self.types.re_static,
+ self.lang_items.CStr.map_or_else(
+ || self.err_ty(),
+ |strukt| Ty::new_adt(self.interner(), strukt.into(), self.types.empty_args),
+ ),
Mutability::Not,
- static_lifetime(),
- self.resolve_lang_item(LangItem::CStr)
- .and_then(LangItemTarget::as_struct)
- .map_or_else(
- || self.err_ty(),
- |strukt| {
- TyKind::Adt(AdtId(strukt.into()), Substitution::empty(Interner))
- .intern(Interner)
- },
- ),
- )
- .intern(Interner),
- Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner),
+ ),
+ Literal::Char(..) => self.types.char,
Literal::Int(_v, ty) => match ty {
- Some(int_ty) => {
- TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty)))
- .intern(Interner)
- }
+ Some(int_ty) => match int_ty {
+ hir_def::builtin_type::BuiltinInt::Isize => self.types.isize,
+ hir_def::builtin_type::BuiltinInt::I8 => self.types.i8,
+ hir_def::builtin_type::BuiltinInt::I16 => self.types.i16,
+ hir_def::builtin_type::BuiltinInt::I32 => self.types.i32,
+ hir_def::builtin_type::BuiltinInt::I64 => self.types.i64,
+ hir_def::builtin_type::BuiltinInt::I128 => self.types.i128,
+ },
None => {
let expected_ty = expected.to_option(&mut self.table);
tracing::debug!(?expected_ty);
- let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) {
- Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty,
- Some(TyKind::Scalar(Scalar::Char)) => {
- Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner))
- }
- Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => {
- Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner))
+ let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) {
+ Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty,
+ Some(TyKind::Char) => Some(self.types.u8),
+ Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => {
+ Some(self.types.usize)
}
_ => None,
};
- opt_ty.unwrap_or_else(|| self.table.new_integer_var())
+ opt_ty.unwrap_or_else(|| self.table.next_int_var())
}
},
Literal::Uint(_v, ty) => match ty {
- Some(int_ty) => {
- TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty)))
- .intern(Interner)
- }
+ Some(int_ty) => match int_ty {
+ hir_def::builtin_type::BuiltinUint::Usize => self.types.usize,
+ hir_def::builtin_type::BuiltinUint::U8 => self.types.u8,
+ hir_def::builtin_type::BuiltinUint::U16 => self.types.u16,
+ hir_def::builtin_type::BuiltinUint::U32 => self.types.u32,
+ hir_def::builtin_type::BuiltinUint::U64 => self.types.u64,
+ hir_def::builtin_type::BuiltinUint::U128 => self.types.u128,
+ },
None => {
let expected_ty = expected.to_option(&mut self.table);
- let opt_ty = match expected_ty.as_ref().map(|it| it.kind(Interner)) {
- Some(TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))) => expected_ty,
- Some(TyKind::Scalar(Scalar::Char)) => {
- Some(TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner))
- }
- Some(TyKind::Raw(..) | TyKind::FnDef(..) | TyKind::Function(..)) => {
- Some(TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner))
+ let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) {
+ Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty,
+ Some(TyKind::Char) => Some(self.types.u8),
+ Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => {
+ Some(self.types.usize)
}
_ => None,
};
- opt_ty.unwrap_or_else(|| self.table.new_integer_var())
+ opt_ty.unwrap_or_else(|| self.table.next_int_var())
}
},
Literal::Float(_v, ty) => match ty {
- Some(float_ty) => {
- TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty)))
- .intern(Interner)
- }
+ Some(float_ty) => match float_ty {
+ hir_def::builtin_type::BuiltinFloat::F16 => self.types.f16,
+ hir_def::builtin_type::BuiltinFloat::F32 => self.types.f32,
+ hir_def::builtin_type::BuiltinFloat::F64 => self.types.f64,
+ hir_def::builtin_type::BuiltinFloat::F128 => self.types.f128,
+ },
None => {
- let opt_ty = expected.to_option(&mut self.table).filter(|ty| {
- matches!(ty.kind(Interner), TyKind::Scalar(Scalar::Float(_)))
- });
- opt_ty.unwrap_or_else(|| self.table.new_float_var())
+ let opt_ty = expected
+ .to_option(&mut self.table)
+ .filter(|ty| matches!(ty.kind(), TyKind::Float(_)));
+ opt_ty.unwrap_or_else(|| self.table.next_float_var())
}
},
},
@@ -1048,13 +947,10 @@ impl<'db> InferenceContext<'db> {
// Underscore expression is an error, we render a specialized diagnostic
// to let the user know what type is expected though.
let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty());
- self.push_diagnostic(InferenceDiagnostic::TypedHole {
- expr: tgt_expr,
- expected: expected.clone(),
- });
+ self.push_diagnostic(InferenceDiagnostic::TypedHole { expr: tgt_expr, expected });
expected
}
- Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
+ Expr::OffsetOf(_) => self.types.usize,
Expr::InlineAsm(asm) => {
let check_expr_asm_operand = |this: &mut Self, expr, is_input: bool| {
let ty = this.infer_expr_no_expect(expr, ExprIsRead::Yes);
@@ -1067,29 +963,31 @@ impl<'db> InferenceContext<'db> {
// allows them to be inferred based on how they are used later in the
// function.
if is_input {
- let ty = this.table.structurally_resolve_type(&ty);
- match ty.kind(Interner) {
+ let ty = this.table.structurally_resolve_type(ty);
+ match ty.kind() {
TyKind::FnDef(def, parameters) => {
- let fnptr_ty = TyKind::Function(
- CallableSig::from_def(this.db, *def, parameters).to_fn_ptr(),
- )
- .intern(Interner);
+ let fnptr_ty = Ty::new_fn_ptr(
+ this.interner(),
+ this.interner()
+ .fn_sig(def)
+ .instantiate(this.interner(), parameters),
+ );
_ = this.coerce(
expr.into(),
- ty.to_nextsolver(this.table.interner),
- fnptr_ty.to_nextsolver(this.table.interner),
+ ty,
+ fnptr_ty,
AllowTwoPhase::No,
- CoerceNever::Yes,
+ ExprIsRead::Yes,
);
}
- TyKind::Ref(mutbl, _, base_ty) => {
- let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner);
+ TyKind::Ref(_, base_ty, mutbl) => {
+ let ptr_ty = Ty::new_ptr(this.interner(), base_ty, mutbl);
_ = this.coerce(
expr.into(),
- ty.to_nextsolver(this.table.interner),
- ptr_ty.to_nextsolver(this.table.interner),
+ ty,
+ ptr_ty,
AllowTwoPhase::No,
- CoerceNever::Yes,
+ ExprIsRead::Yes,
);
}
_ => {}
@@ -1113,7 +1011,7 @@ impl<'db> InferenceContext<'db> {
AsmOperand::Label(expr) => {
self.infer_expr(
expr,
- &Expectation::HasType(self.result.standard_types.unit.clone()),
+ &Expectation::HasType(self.types.unit),
ExprIsRead::No,
);
}
@@ -1123,17 +1021,13 @@ impl<'db> InferenceContext<'db> {
// FIXME: `sym` should report for things that are not functions or statics.
AsmOperand::Sym(_) => (),
});
- if diverge {
- self.result.standard_types.never.clone()
- } else {
- self.result.standard_types.unit.clone()
- }
+ if diverge { self.types.never } else { self.types.unit }
}
};
// use a new type variable if we got unknown here
let ty = self.insert_type_vars_shallow(ty);
- self.write_expr_ty(tgt_expr, ty.clone());
- if self.resolve_ty_shallow(&ty).is_never()
+ self.write_expr_ty(tgt_expr, ty);
+ if self.shallow_resolve(ty).is_never()
&& self.expr_guaranteed_to_constitute_read_for_never(tgt_expr, is_read)
{
// Any expression that produces a value of type `!` must have diverged
@@ -1142,7 +1036,78 @@ impl<'db> InferenceContext<'db> {
ty
}
- fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty {
+ fn demand_scrutinee_type(
+ &mut self,
+ scrut: ExprId,
+ contains_ref_bindings: bool,
+ no_arms: bool,
+ scrutinee_is_read: ExprIsRead,
+ ) -> Ty<'db> {
+ // Not entirely obvious: if matches may create ref bindings, we want to
+ // use the *precise* type of the scrutinee, *not* some supertype, as
+ // the "scrutinee type" (issue #23116).
+ //
+ // arielb1 [writes here in this comment thread][c] that there
+ // is certainly *some* potential danger, e.g., for an example
+ // like:
+ //
+ // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956
+ //
+ // ```
+ // let Foo(x) = f()[0];
+ // ```
+ //
+ // Then if the pattern matches by reference, we want to match
+ // `f()[0]` as a lexpr, so we can't allow it to be
+ // coerced. But if the pattern matches by value, `f()[0]` is
+ // still syntactically a lexpr, but we *do* want to allow
+ // coercions.
+ //
+ // However, *likely* we are ok with allowing coercions to
+ // happen if there are no explicit ref mut patterns - all
+ // implicit ref mut patterns must occur behind a reference, so
+ // they will have the "correct" variance and lifetime.
+ //
+ // This does mean that the following pattern would be legal:
+ //
+ // ```
+ // struct Foo(Bar);
+ // struct Bar(u32);
+ // impl Deref for Foo {
+ // type Target = Bar;
+ // fn deref(&self) -> &Bar { &self.0 }
+ // }
+ // impl DerefMut for Foo {
+ // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 }
+ // }
+ // fn foo(x: &mut Foo) {
+ // {
+ // let Bar(z): &mut Bar = x;
+ // *z = 42;
+ // }
+ // assert_eq!(foo.0.0, 42);
+ // }
+ // ```
+ //
+ // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
+ // is problematic as the HIR is being scraped, but ref bindings may be
+ // implicit after #42640. We need to make sure that pat_adjustments
+ // (once introduced) is populated by the time we get here.
+ //
+ // See #44848.
+ if contains_ref_bindings || no_arms {
+ self.infer_expr_no_expect(scrut, scrutinee_is_read)
+ } else {
+ // ...but otherwise we want to use any supertype of the
+ // scrutinee. This is sort of a workaround, see note (*) in
+ // `check_pat` for some details.
+ let scrut_ty = self.table.next_ty_var();
+ self.infer_expr_coerce_never(scrut, &Expectation::HasType(scrut_ty), scrutinee_is_read);
+ scrut_ty
+ }
+ }
+
+ fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty<'db> {
let g = self.resolver.update_to_inner_scope(self.db, self.owner, scope_id);
let ty = match self.infer_path(path, id) {
Some(ty) => ty,
@@ -1158,38 +1123,71 @@ impl<'db> InferenceContext<'db> {
ty
}
+ fn infer_unop_expr(
+ &mut self,
+ unop: UnaryOp,
+ oprnd: ExprId,
+ expected: &Expectation<'db>,
+ expr: ExprId,
+ ) -> Ty<'db> {
+ let expected_inner = match unop {
+ UnaryOp::Not | UnaryOp::Neg => expected,
+ UnaryOp::Deref => &Expectation::None,
+ };
+ let mut oprnd_t = self.infer_expr_inner(oprnd, expected_inner, ExprIsRead::Yes);
+
+ oprnd_t = self.table.structurally_resolve_type(oprnd_t);
+ match unop {
+ UnaryOp::Deref => {
+ if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
+ oprnd_t = ty;
+ } else {
+ // FIXME: Report an error.
+ oprnd_t = self.types.error;
+ }
+ }
+ UnaryOp::Not => {
+ let result = self.infer_user_unop(expr, oprnd_t, unop);
+ // If it's builtin, we can reuse the type, this helps inference.
+ if !(oprnd_t.is_integral() || oprnd_t.kind() == TyKind::Bool) {
+ oprnd_t = result;
+ }
+ }
+ UnaryOp::Neg => {
+ let result = self.infer_user_unop(expr, oprnd_t, unop);
+ // If it's builtin, we can reuse the type, this helps inference.
+ if !oprnd_t.is_numeric() {
+ oprnd_t = result;
+ }
+ }
+ }
+ oprnd_t
+ }
+
fn infer_async_block(
&mut self,
tgt_expr: ExprId,
id: &Option<BlockId>,
statements: &[Statement],
tail: &Option<ExprId>,
- ) -> Ty {
- let ret_ty = self.table.new_type_var();
+ ) -> Ty<'db> {
+ let ret_ty = self.table.next_ty_var();
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
- let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
- let prev_ret_coercion = self
- .return_coercion
- .replace(CoerceMany::new(ret_ty.to_nextsolver(self.table.interner)));
+ let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty);
+ let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(ret_ty));
// FIXME: We should handle async blocks like we handle closures
let expected = &Expectation::has_type(ret_ty);
let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
let ty = this.infer_block(tgt_expr, *id, statements, *tail, None, expected);
if let Some(target) = expected.only_has_type(&mut this.table) {
- match this.coerce(
- tgt_expr.into(),
- ty.to_nextsolver(this.table.interner),
- target.to_nextsolver(this.table.interner),
- AllowTwoPhase::No,
- CoerceNever::Yes,
- ) {
- Ok(res) => res.to_chalk(this.table.interner),
+ match this.coerce(tgt_expr.into(), ty, target, AllowTwoPhase::No, ExprIsRead::Yes) {
+ Ok(res) => res,
Err(_) => {
- this.result.type_mismatches.insert(
- tgt_expr.into(),
- TypeMismatch { expected: target.clone(), actual: ty.clone() },
- );
+ this.result
+ .type_mismatches
+ .get_or_insert_default()
+ .insert(tgt_expr.into(), TypeMismatch { expected: target, actual: ty });
target
}
}
@@ -1207,138 +1205,152 @@ impl<'db> InferenceContext<'db> {
pub(crate) fn lower_async_block_type_impl_trait(
&mut self,
- inner_ty: Ty,
+ inner_ty: Ty<'db>,
tgt_expr: ExprId,
- ) -> Ty {
- // Use the first type parameter as the output type of future.
- // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
- let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr);
- let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
- TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)).intern(Interner)
+ ) -> Ty<'db> {
+ let coroutine_id = InternedCoroutine(self.owner, tgt_expr);
+ let coroutine_id = self.db.intern_coroutine(coroutine_id).into();
+ let parent_args = GenericArgs::identity_for_item(self.interner(), self.generic_def.into());
+ Ty::new_coroutine(
+ self.interner(),
+ coroutine_id,
+ CoroutineArgs::new(
+ self.interner(),
+ CoroutineArgsParts {
+ parent_args,
+ kind_ty: self.types.unit,
+ // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems.
+ resume_ty: self.types.unit,
+ yield_ty: self.types.unit,
+ return_ty: inner_ty,
+ // FIXME: Infer upvars.
+ tupled_upvars_ty: self.types.unit,
+ },
+ )
+ .args,
+ )
}
pub(crate) fn write_fn_trait_method_resolution(
&mut self,
fn_x: FnTrait,
- derefed_callee: &Ty,
- adjustments: &mut Vec<Adjustment>,
- callee_ty: &Ty,
- params: &[Ty],
+ derefed_callee: Ty<'db>,
+ adjustments: &mut Vec<Adjustment<'db>>,
+ callee_ty: Ty<'db>,
+ params: &[Ty<'db>],
tgt_expr: ExprId,
) {
match fn_x {
FnTrait::FnOnce | FnTrait::AsyncFnOnce => (),
FnTrait::FnMut | FnTrait::AsyncFnMut => {
- if let TyKind::Ref(Mutability::Mut, lt, inner) = derefed_callee.kind(Interner) {
+ if let TyKind::Ref(lt, inner, Mutability::Mut) = derefed_callee.kind() {
if adjustments
.last()
.map(|it| matches!(it.kind, Adjust::Borrow(_)))
.unwrap_or(true)
{
// prefer reborrow to move
- adjustments
- .push(Adjustment { kind: Adjust::Deref(None), target: inner.clone() });
+ adjustments.push(Adjustment { kind: Adjust::Deref(None), target: inner });
adjustments.push(Adjustment::borrow(
+ self.interner(),
Mutability::Mut,
- inner.clone(),
- lt.clone(),
+ inner,
+ lt,
))
}
} else {
adjustments.push(Adjustment::borrow(
+ self.interner(),
Mutability::Mut,
- derefed_callee.clone(),
- self.table.new_lifetime_var(),
+ derefed_callee,
+ self.table.next_region_var(),
));
}
}
FnTrait::Fn | FnTrait::AsyncFn => {
- if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) {
+ if !matches!(derefed_callee.kind(), TyKind::Ref(_, _, Mutability::Not)) {
adjustments.push(Adjustment::borrow(
+ self.interner(),
Mutability::Not,
- derefed_callee.clone(),
- self.table.new_lifetime_var(),
+ derefed_callee,
+ self.table.next_region_var(),
));
}
}
}
- let Some(trait_) = fn_x.get_id(self.db, self.table.trait_env.krate) else {
+ let Some(trait_) = fn_x.get_id(self.lang_items) else {
return;
};
let trait_data = trait_.trait_items(self.db);
if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) {
- let subst = TyBuilder::subst_for_def(self.db, trait_, None)
- .push(callee_ty.clone())
- .push(TyBuilder::tuple_with(params.iter().cloned()))
- .build();
+ let subst = GenericArgs::new_from_iter(
+ self.interner(),
+ [
+ callee_ty.into(),
+ Ty::new_tup_from_iter(self.interner(), params.iter().copied()).into(),
+ ],
+ );
self.write_method_resolution(tgt_expr, func, subst);
}
}
- fn infer_expr_array(
- &mut self,
- array: &Array,
- expected: &Expectation,
- ) -> chalk_ir::Ty<Interner> {
- let elem_ty = match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) {
- Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
- _ => self.table.new_type_var(),
+ fn infer_expr_array(&mut self, array: &Array, expected: &Expectation<'db>) -> Ty<'db> {
+ let elem_ty = match expected
+ .to_option(&mut self.table)
+ .map(|t| self.table.try_structurally_resolve_type(t).kind())
+ {
+ Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st,
+ _ => self.table.next_ty_var(),
};
let krate = self.resolver.krate();
- let expected = Expectation::has_type(elem_ty.clone());
+ let expected = Expectation::has_type(elem_ty);
let (elem_ty, len) = match array {
Array::ElementList { elements, .. } if elements.is_empty() => {
(elem_ty, consteval::usize_const(self.db, Some(0), krate))
}
Array::ElementList { elements, .. } => {
- let mut coerce = CoerceMany::with_coercion_sites(
- elem_ty.to_nextsolver(self.table.interner),
- elements,
- );
+ let mut coerce = CoerceMany::with_coercion_sites(elem_ty, elements);
for &expr in elements.iter() {
let cur_elem_ty = self.infer_expr_inner(expr, &expected, ExprIsRead::Yes);
coerce.coerce(
self,
&ObligationCause::new(),
expr,
- cur_elem_ty.to_nextsolver(self.table.interner),
+ cur_elem_ty,
+ ExprIsRead::Yes,
);
}
(
- coerce.complete(self).to_chalk(self.table.interner),
+ coerce.complete(self),
consteval::usize_const(self.db, Some(elements.len() as u128), krate),
)
}
&Array::Repeat { initializer, repeat } => {
self.infer_expr_coerce(
initializer,
- &Expectation::has_type(elem_ty.clone()),
+ &Expectation::has_type(elem_ty),
ExprIsRead::Yes,
);
- let usize = TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner);
- match self.body[repeat] {
+ let usize = self.types.usize;
+ let len = match self.body[repeat] {
Expr::Underscore => {
self.write_expr_ty(repeat, usize);
+ self.table.next_const_var()
}
- _ => _ = self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes),
- }
+ _ => {
+ self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes);
+ consteval::eval_to_const(repeat, self)
+ }
+ };
- (
- elem_ty,
- consteval::eval_to_const(
- repeat,
- ParamLoweringMode::Placeholder,
- self,
- DebruijnIndex::INNERMOST,
- ),
- )
+ (elem_ty, len)
}
};
// Try to evaluate unevaluated constant, and insert variable if is not possible.
let len = self.table.insert_const_vars_shallow(len);
- TyKind::Array(elem_ty, len).intern(Interner)
+ Ty::new_array_with_const_len(self.interner(), elem_ty, len)
}
pub(super) fn infer_return(&mut self, expr: ExprId) {
@@ -1346,28 +1358,28 @@ impl<'db> InferenceContext<'db> {
.return_coercion
.as_mut()
.expect("infer_return called outside function body")
- .expected_ty()
- .to_chalk(self.table.interner);
+ .expected_ty();
let return_expr_ty =
self.infer_expr_inner(expr, &Expectation::HasType(ret_ty), ExprIsRead::Yes);
let mut coerce_many = self.return_coercion.take().unwrap();
- coerce_many.coerce(
- self,
- &ObligationCause::new(),
- expr,
- return_expr_ty.to_nextsolver(self.table.interner),
- );
+ coerce_many.coerce(self, &ObligationCause::new(), expr, return_expr_ty, ExprIsRead::Yes);
self.return_coercion = Some(coerce_many);
}
- fn infer_expr_return(&mut self, ret: ExprId, expr: Option<ExprId>) -> Ty {
+ fn infer_expr_return(&mut self, ret: ExprId, expr: Option<ExprId>) -> Ty<'db> {
match self.return_coercion {
Some(_) => {
if let Some(expr) = expr {
self.infer_return(expr);
} else {
let mut coerce = self.return_coercion.take().unwrap();
- coerce.coerce_forced_unit(self, ret, &ObligationCause::new(), true);
+ coerce.coerce_forced_unit(
+ self,
+ ret,
+ &ObligationCause::new(),
+ true,
+ ExprIsRead::Yes,
+ );
self.return_coercion = Some(coerce);
}
}
@@ -1378,23 +1390,20 @@ impl<'db> InferenceContext<'db> {
}
}
}
- self.result.standard_types.never.clone()
+ self.types.never
}
- fn infer_expr_become(&mut self, expr: ExprId) -> Ty {
+ fn infer_expr_become(&mut self, expr: ExprId) -> Ty<'db> {
match &self.return_coercion {
Some(return_coercion) => {
- let ret_ty = return_coercion.expected_ty().to_chalk(self.table.interner);
+ let ret_ty = return_coercion.expected_ty();
- let call_expr_ty = self.infer_expr_inner(
- expr,
- &Expectation::HasType(ret_ty.clone()),
- ExprIsRead::Yes,
- );
+ let call_expr_ty =
+ self.infer_expr_inner(expr, &Expectation::HasType(ret_ty), ExprIsRead::Yes);
// 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.unify(call_expr_ty, ret_ty);
}
None => {
// FIXME: diagnose `become` outside of functions
@@ -1402,10 +1411,10 @@ impl<'db> InferenceContext<'db> {
}
}
- self.result.standard_types.never.clone()
+ self.types.never
}
- fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
+ fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation<'db>) -> Ty<'db> {
if let Some(box_id) = self.resolve_boxed_box() {
let table = &mut self.table;
let inner_exp = expected
@@ -1414,121 +1423,27 @@ impl<'db> InferenceContext<'db> {
.and_then(|e| e.as_adt())
.filter(|(e_adt, _)| e_adt == &box_id)
.map(|(_, subts)| {
- let g = subts.at(Interner, 0);
- Expectation::rvalue_hint(self, Ty::clone(g.assert_ty_ref(Interner)))
+ let g = subts.type_at(0);
+ Expectation::rvalue_hint(self, g)
})
.unwrap_or_else(Expectation::none);
let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp, ExprIsRead::Yes);
- TyBuilder::adt(self.db, box_id)
- .push(inner_ty)
- .fill_with_defaults(self.db, || self.table.new_type_var())
- .build()
+ Ty::new_adt(
+ self.interner(),
+ box_id,
+ GenericArgs::fill_with_defaults(
+ self.interner(),
+ box_id.into(),
+ [inner_ty.into()],
+ |_, id, _| self.table.next_var_for_param(id),
+ ),
+ )
} else {
self.err_ty()
}
}
- fn infer_overloadable_binop(
- &mut self,
- lhs: ExprId,
- op: BinaryOp,
- rhs: ExprId,
- tgt_expr: ExprId,
- ) -> Ty {
- let lhs_expectation = Expectation::none();
- let is_read = if matches!(op, BinaryOp::Assignment { .. }) {
- ExprIsRead::Yes
- } else {
- ExprIsRead::No
- };
- let lhs_ty = self.infer_expr(lhs, &lhs_expectation, is_read);
- let rhs_ty = self.table.new_type_var();
-
- let trait_func = lang_items_for_bin_op(op).and_then(|(name, lang_item)| {
- let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
- let func = trait_id.trait_items(self.db).method_by_name(&name)?;
- Some((trait_id, func))
- });
- let (trait_, func) = match trait_func {
- Some(it) => it,
- None => {
- // HACK: `rhs_ty` is a general inference variable with no clue at all at this
- // point. Passing `lhs_ty` as both operands just to check if `lhs_ty` is a builtin
- // type applicable to `op`.
- let ret_ty = if self.is_builtin_binop(&lhs_ty, &lhs_ty, op) {
- // Assume both operands are builtin so we can continue inference. No guarantee
- // on the correctness, rustc would complain as necessary lang items don't seem
- // to exist anyway.
- self.enforce_builtin_binop_types(&lhs_ty, &rhs_ty, op)
- } else {
- self.err_ty()
- };
-
- self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty), ExprIsRead::Yes);
-
- return ret_ty;
- }
- };
-
- // HACK: We can use this substitution for the function because the function itself doesn't
- // have its own generic parameters.
- let subst = TyBuilder::subst_for_def(self.db, trait_, None);
- if subst.remaining() != 2 {
- return Ty::new(Interner, TyKind::Error);
- }
- let subst = subst.push(lhs_ty.clone()).push(rhs_ty.clone()).build();
-
- self.write_method_resolution(tgt_expr, func, subst.clone());
-
- let method_ty = self.db.value_ty(func.into()).unwrap().substitute(Interner, &subst);
- self.register_obligations_for_call(&method_ty);
-
- self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()), ExprIsRead::Yes);
-
- let ret_ty = match method_ty.callable_sig(self.db) {
- Some(sig) => {
- let p_left = &sig.params()[0];
- if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. })
- && let TyKind::Ref(mtbl, lt, _) = p_left.kind(Interner)
- {
- self.write_expr_adj(
- lhs,
- Box::new([Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
- target: p_left.clone(),
- }]),
- );
- }
- let p_right = &sig.params()[1];
- if matches!(op, BinaryOp::CmpOp(..))
- && let TyKind::Ref(mtbl, lt, _) = p_right.kind(Interner)
- {
- self.write_expr_adj(
- rhs,
- Box::new([Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
- target: p_right.clone(),
- }]),
- );
- }
- sig.ret().clone()
- }
- None => self.err_ty(),
- };
-
- let ret_ty = self.process_remote_user_written_ty(ret_ty);
-
- if self.is_builtin_binop(&lhs_ty, &rhs_ty, op) {
- // use knowledge of built-in binary ops, which can sometimes help inference
- let builtin_ret = self.enforce_builtin_binop_types(&lhs_ty, &rhs_ty, op);
- self.unify(&builtin_ret, &ret_ty);
- builtin_ret
- } else {
- ret_ty
- }
- }
-
fn infer_block(
&mut self,
expr: ExprId,
@@ -1536,8 +1451,8 @@ impl<'db> InferenceContext<'db> {
statements: &[Statement],
tail: Option<ExprId>,
label: Option<LabelId>,
- expected: &Expectation,
- ) -> Ty {
+ expected: &Expectation<'db>,
+ ) -> Ty<'db> {
let coerce_ty = expected.coercion_target_type(&mut self.table);
let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
let prev_env = block_id.map(|block_id| {
@@ -1554,7 +1469,7 @@ impl<'db> InferenceContext<'db> {
let decl_ty = type_ref
.as_ref()
.map(|&tr| this.make_body_ty(tr))
- .unwrap_or_else(|| this.table.new_type_var());
+ .unwrap_or_else(|| this.table.next_ty_var());
let ty = if let Some(expr) = initializer {
// If we have a subpattern that performs a read, we want to consider this
@@ -1568,13 +1483,13 @@ impl<'db> InferenceContext<'db> {
let ty = if contains_explicit_ref_binding(this.body, *pat) {
this.infer_expr(
*expr,
- &Expectation::has_type(decl_ty.clone()),
+ &Expectation::has_type(decl_ty),
target_is_read,
)
} else {
this.infer_expr_coerce(
*expr,
- &Expectation::has_type(decl_ty.clone()),
+ &Expectation::has_type(decl_ty),
target_is_read,
)
};
@@ -1587,13 +1502,13 @@ impl<'db> InferenceContext<'db> {
origin: DeclOrigin::LocalDecl { has_else: else_branch.is_some() },
};
- this.infer_top_pat(*pat, &ty, Some(decl));
+ this.infer_top_pat(*pat, ty, Some(decl));
if let Some(expr) = else_branch {
let previous_diverges =
mem::replace(&mut this.diverges, Diverges::Maybe);
this.infer_expr_coerce(
*expr,
- &Expectation::HasType(this.result.standard_types.never.clone()),
+ &Expectation::HasType(this.types.never),
ExprIsRead::Yes,
);
this.diverges = previous_diverges;
@@ -1605,7 +1520,7 @@ impl<'db> InferenceContext<'db> {
} else {
this.infer_expr_coerce(
expr,
- &Expectation::HasType(this.result.standard_types.unit.clone()),
+ &Expectation::HasType(this.types.unit),
ExprIsRead::Yes,
);
}
@@ -1629,40 +1544,29 @@ impl<'db> InferenceContext<'db> {
// we don't even make an attempt at coercion
this.table.new_maybe_never_var()
} else if let Some(t) = expected.only_has_type(&mut this.table) {
- let coerce_never = if this
- .expr_guaranteed_to_constitute_read_for_never(expr, ExprIsRead::Yes)
- {
- CoerceNever::Yes
- } else {
- CoerceNever::No
- };
if this
.coerce(
expr.into(),
- this.result.standard_types.unit.to_nextsolver(this.table.interner),
- t.to_nextsolver(this.table.interner),
+ this.types.unit,
+ t,
AllowTwoPhase::No,
- coerce_never,
+ ExprIsRead::Yes,
)
.is_err()
{
- this.result.type_mismatches.insert(
+ this.result.type_mismatches.get_or_insert_default().insert(
expr.into(),
- TypeMismatch {
- expected: t.clone(),
- actual: this.result.standard_types.unit.clone(),
- },
+ TypeMismatch { expected: t, actual: this.types.unit },
);
}
t
} else {
- this.result.standard_types.unit.clone()
+ this.types.unit
}
}
});
self.resolver.reset_to_guard(g);
if let Some(prev_env) = prev_env {
- self.table.param_env = prev_env.env.to_nextsolver(self.table.interner);
self.table.trait_env = prev_env;
}
@@ -1671,32 +1575,30 @@ impl<'db> InferenceContext<'db> {
fn lookup_field(
&mut self,
- receiver_ty: &Ty,
+ receiver_ty: Ty<'db>,
name: &Name,
- ) -> Option<(Ty, Either<FieldId, TupleFieldId>, Vec<Adjustment>, bool)> {
- let interner = self.table.interner;
- let mut autoderef = self.table.autoderef(receiver_ty.to_nextsolver(self.table.interner));
+ ) -> Option<(Ty<'db>, Either<FieldId, TupleFieldId>, Vec<Adjustment<'db>>, bool)> {
+ let interner = self.interner();
+ let mut autoderef = self.table.autoderef_with_tracking(receiver_ty);
let mut private_field = None;
let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
let (field_id, parameters) = match derefed_ty.kind() {
- crate::next_solver::TyKind::Tuple(substs) => {
+ TyKind::Tuple(substs) => {
return name.as_tuple_index().and_then(|idx| {
substs.as_slice().get(idx).copied().map(|ty| {
(
Either::Right(TupleFieldId {
tuple: TupleId(
- self.tuple_field_accesses_rev
- .insert_full(substs.to_chalk(interner))
- .0 as u32,
+ self.tuple_field_accesses_rev.insert_full(substs).0 as u32,
),
index: idx as u32,
}),
- ty.to_chalk(interner),
+ ty,
)
})
});
}
- crate::next_solver::TyKind::Adt(adt, parameters) => match adt.def_id().0 {
+ TyKind::Adt(adt, parameters) => match adt.def_id().0 {
hir_def::AdtId::StructId(s) => {
let local_id = s.fields(self.db).field(name)?;
let field = FieldId { parent: s.into(), local_id };
@@ -1711,34 +1613,33 @@ impl<'db> InferenceContext<'db> {
},
_ => return None,
};
- let parameters: crate::Substitution = parameters.to_chalk(interner);
let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id]
.is_visible_from(self.db, self.resolver.module());
if !is_visible {
if private_field.is_none() {
- private_field = Some((field_id, parameters.clone()));
+ private_field = Some((field_id, parameters));
}
return None;
}
let ty = self.db.field_types(field_id.parent)[field_id.local_id]
- .clone()
- .substitute(Interner, &parameters);
+ .instantiate(interner, parameters);
Some((Either::Left(field_id), ty))
});
Some(match res {
Some((field_id, ty)) => {
- let adjustments = autoderef.adjust_steps();
+ let adjustments =
+ self.table.register_infer_ok(autoderef.adjust_steps_as_infer_ok());
let ty = self.process_remote_user_written_ty(ty);
(ty, field_id, adjustments, true)
}
None => {
let (field_id, subst) = private_field?;
- let adjustments = autoderef.adjust_steps();
+ let adjustments =
+ self.table.register_infer_ok(autoderef.adjust_steps_as_infer_ok());
let ty = self.db.field_types(field_id.parent)[field_id.local_id]
- .clone()
- .substitute(Interner, &subst);
+ .instantiate(self.interner(), subst);
let ty = self.process_remote_user_written_ty(ty);
(ty, Either::Left(field_id), adjustments, false)
@@ -1751,10 +1652,11 @@ impl<'db> InferenceContext<'db> {
tgt_expr: ExprId,
receiver: ExprId,
name: &Name,
- expected: &Expectation,
- ) -> Ty {
+ expected: &Expectation<'db>,
+ ) -> Ty<'db> {
// Field projections don't constitute reads.
let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::No);
+ let receiver_ty = self.table.structurally_resolve_type(receiver_ty);
if name.is_missing() {
// Bail out early, don't even try to look up field. Also, we don't issue an unresolved
@@ -1762,7 +1664,7 @@ impl<'db> InferenceContext<'db> {
return self.err_ty();
}
- match self.lookup_field(&receiver_ty, name) {
+ match self.lookup_field(receiver_ty, name) {
Some((ty, field_id, adjustments, is_public)) => {
self.write_expr_adj(receiver, adjustments.into_boxed_slice());
self.result.field_resolutions.insert(tgt_expr, field_id);
@@ -1778,90 +1680,82 @@ impl<'db> InferenceContext<'db> {
None => {
// no field found, lets attempt to resolve it like a function so that IDE things
// work out while people are typing
- let canonicalized_receiver =
- self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner));
- let resolved = method_resolution::lookup_method(
- self.db,
- &canonicalized_receiver,
- self.table.trait_env.clone(),
- self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
- VisibleFromModule::Filter(self.resolver.module()),
- name,
+ let resolved = self.lookup_method_including_private(
+ receiver_ty,
+ name.clone(),
+ None,
+ receiver,
+ tgt_expr,
);
self.push_diagnostic(InferenceDiagnostic::UnresolvedField {
expr: tgt_expr,
- receiver: receiver_ty.clone(),
+ receiver: receiver_ty,
name: name.clone(),
- method_with_same_name_exists: resolved.is_some(),
+ method_with_same_name_exists: resolved.is_ok(),
});
match resolved {
- Some((adjust, func, _)) => {
- let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
- let substs = self.substs_for_method_call(tgt_expr, func.into(), None);
- self.write_expr_adj(receiver, adjustments.into_boxed_slice());
- self.write_method_resolution(tgt_expr, func, substs.clone());
-
- self.check_method_call(
- tgt_expr,
- &[],
- self.db.value_ty(func.into()).unwrap(),
- substs,
- ty,
- expected,
- )
+ Ok((func, _is_visible)) => {
+ self.check_method_call(tgt_expr, &[], func.sig, receiver_ty, expected)
}
- None => self.err_ty(),
+ Err(_) => self.err_ty(),
}
}
}
}
+ fn instantiate_erroneous_method(&mut self, def_id: FunctionId) -> MethodCallee<'db> {
+ // FIXME: Using fresh infer vars for the method args isn't optimal,
+ // we can do better by going thorough the full probe/confirm machinery.
+ let args = self.table.fresh_args_for_item(def_id.into());
+ let sig = self.db.callable_item_signature(def_id.into()).instantiate(self.interner(), args);
+ let sig =
+ self.infcx().instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, sig);
+ MethodCallee { def_id, args, sig }
+ }
+
fn infer_call(
&mut self,
tgt_expr: ExprId,
callee: ExprId,
args: &[ExprId],
- expected: &Expectation,
- ) -> Ty {
+ expected: &Expectation<'db>,
+ ) -> Ty<'db> {
let callee_ty = self.infer_expr(callee, &Expectation::none(), ExprIsRead::Yes);
- let interner = self.table.interner;
- let mut derefs = self.table.autoderef(callee_ty.to_nextsolver(interner));
+ let callee_ty = self.table.try_structurally_resolve_type(callee_ty);
+ let interner = self.interner();
+ let mut derefs = InferenceContextAutoderef::new_from_inference_context(self, callee_ty);
let (res, derefed_callee) = loop {
let Some((callee_deref_ty, _)) = derefs.next() else {
- break (None, callee_ty.clone());
+ break (None, callee_ty);
};
- let callee_deref_ty = callee_deref_ty.to_chalk(interner);
- if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) {
+ if let Some(res) = derefs.ctx().table.callable_sig(callee_deref_ty, args.len()) {
break (Some(res), callee_deref_ty);
}
};
// if the function is unresolved, we use is_varargs=true to
// suppress the arg count diagnostic here
- let is_varargs =
- derefed_callee.callable_sig(self.db).is_some_and(|sig| sig.is_varargs) || res.is_none();
+ let is_varargs = derefed_callee.callable_sig(interner).is_some_and(|sig| sig.c_variadic())
+ || res.is_none();
let (param_tys, ret_ty) = match res {
Some((func, params, ret_ty)) => {
- let params_chalk =
- params.iter().map(|param| param.to_chalk(interner)).collect::<Vec<_>>();
- let mut adjustments = derefs.adjust_steps();
+ let infer_ok = derefs.adjust_steps_as_infer_ok();
+ let mut adjustments = self.table.register_infer_ok(infer_ok);
if let Some(fn_x) = func {
self.write_fn_trait_method_resolution(
fn_x,
- &derefed_callee,
+ derefed_callee,
&mut adjustments,
- &callee_ty,
- &params_chalk,
+ callee_ty,
+ &params,
tgt_expr,
);
}
- if let &TyKind::Closure(c, _) =
- self.table.resolve_completely(callee_ty.clone()).kind(Interner)
- {
+ if let TyKind::Closure(c, _) = self.table.resolve_completely(callee_ty).kind() {
self.add_current_closure_dependency(c.into());
self.deferred_closures.entry(c.into()).or_default().push((
- derefed_callee.clone(),
- callee_ty.clone(),
- params_chalk,
+ derefed_callee,
+ callee_ty,
+ params.clone(),
tgt_expr,
));
}
@@ -1871,9 +1765,9 @@ impl<'db> InferenceContext<'db> {
None => {
self.push_diagnostic(InferenceDiagnostic::ExpectedFunction {
call_expr: tgt_expr,
- found: callee_ty.clone(),
+ found: callee_ty,
});
- (Vec::new(), crate::next_solver::Ty::new_error(interner, ErrorGuaranteed))
+ (Vec::new(), Ty::new_error(interner, ErrorGuaranteed))
}
};
let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
@@ -1893,14 +1787,14 @@ impl<'db> InferenceContext<'db> {
&mut self,
tgt_expr: ExprId,
args: &[ExprId],
- callee_ty: Ty,
- param_tys: &[crate::next_solver::Ty<'db>],
- ret_ty: crate::next_solver::Ty<'db>,
+ callee_ty: Ty<'db>,
+ param_tys: &[Ty<'db>],
+ ret_ty: Ty<'db>,
indices_to_skip: &[u32],
is_varargs: bool,
- expected: &Expectation,
- ) -> Ty {
- self.register_obligations_for_call(&callee_ty);
+ expected: &Expectation<'db>,
+ ) -> Ty<'db> {
+ self.register_obligations_for_call(callee_ty);
self.check_call_arguments(
tgt_expr,
@@ -1911,7 +1805,7 @@ impl<'db> InferenceContext<'db> {
indices_to_skip,
is_varargs,
);
- self.table.normalize_associated_types_in_ns(ret_ty).to_chalk(self.table.interner)
+ ret_ty
}
fn infer_method_call(
@@ -1920,63 +1814,33 @@ impl<'db> InferenceContext<'db> {
receiver: ExprId,
args: &[ExprId],
method_name: &Name,
- generic_args: Option<&GenericArgs>,
- expected: &Expectation,
- ) -> Ty {
+ generic_args: Option<&HirGenericArgs>,
+ expected: &Expectation<'db>,
+ ) -> Ty<'db> {
let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none(), ExprIsRead::Yes);
- let receiver_ty = self.table.structurally_resolve_type(&receiver_ty);
-
- if matches!(
- receiver_ty.kind(Interner),
- TyKind::Error | TyKind::InferenceVar(_, TyVariableKind::General)
- ) {
- // Don't probe on error type, or on a fully unresolved infer var.
- // FIXME: Emit an error if we're probing on an infer var (type annotations needed).
- for &arg in args {
- // Make sure we infer and record the arguments.
- self.infer_expr_no_expect(arg, ExprIsRead::Yes);
- }
- return receiver_ty;
- }
+ let receiver_ty = self.table.try_structurally_resolve_type(receiver_ty);
- let canonicalized_receiver =
- self.canonicalize(receiver_ty.clone().to_nextsolver(self.table.interner));
-
- let resolved = method_resolution::lookup_method(
- self.db,
- &canonicalized_receiver,
- self.table.trait_env.clone(),
- self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
- VisibleFromModule::Filter(self.resolver.module()),
- method_name,
+ let resolved = self.lookup_method_including_private(
+ receiver_ty,
+ method_name.clone(),
+ generic_args,
+ receiver,
+ tgt_expr,
);
match resolved {
- Some((adjust, func, visible)) => {
+ Ok((func, visible)) => {
if !visible {
self.push_diagnostic(InferenceDiagnostic::PrivateAssocItem {
id: tgt_expr.into(),
- item: func.into(),
+ item: func.def_id.into(),
})
}
-
- let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
- self.write_expr_adj(receiver, adjustments.into_boxed_slice());
-
- let substs = self.substs_for_method_call(tgt_expr, func.into(), generic_args);
- self.write_method_resolution(tgt_expr, func, substs.clone());
- self.check_method_call(
- tgt_expr,
- args,
- self.db.value_ty(func.into()).expect("we have a function def"),
- substs,
- ty,
- expected,
- )
+ self.check_method_call(tgt_expr, args, func.sig, receiver_ty, expected)
}
// Failed to resolve, report diagnostic and try to resolve as call to field access or
// assoc function
- None => {
- let field_with_same_name_exists = match self.lookup_field(&receiver_ty, method_name)
+ Err(_) => {
+ let field_with_same_name_exists = match self.lookup_field(receiver_ty, method_name)
{
Some((ty, field_id, adjustments, _public)) => {
self.write_expr_adj(receiver, adjustments.into_boxed_slice());
@@ -1986,44 +1850,52 @@ impl<'db> InferenceContext<'db> {
None => None,
};
- let assoc_func_with_same_name = method_resolution::iterate_method_candidates(
- &canonicalized_receiver,
- self.db,
- self.table.trait_env.clone(),
- self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
- VisibleFromModule::Filter(self.resolver.module()),
- Some(method_name),
- method_resolution::LookupMode::Path,
- |_ty, item, visible| match item {
- hir_def::AssocItemId::FunctionId(function_id) if visible => {
- Some(function_id)
- }
- _ => None,
- },
- );
+ let assoc_func_with_same_name = self.with_method_resolution(|ctx| {
+ if !matches!(
+ receiver_ty.kind(),
+ TyKind::Infer(InferTy::TyVar(_)) | TyKind::Error(_)
+ ) {
+ ctx.probe_for_name(
+ method_resolution::Mode::Path,
+ method_name.clone(),
+ receiver_ty,
+ )
+ } else {
+ Err(MethodError::ErrorReported)
+ }
+ });
+ let assoc_func_with_same_name = match assoc_func_with_same_name {
+ Ok(method_resolution::Pick {
+ item: CandidateId::FunctionId(def_id), ..
+ })
+ | Err(MethodError::PrivateMatch(method_resolution::Pick {
+ item: CandidateId::FunctionId(def_id),
+ ..
+ })) => Some(self.instantiate_erroneous_method(def_id)),
+ _ => None,
+ };
self.push_diagnostic(InferenceDiagnostic::UnresolvedMethodCall {
expr: tgt_expr,
- receiver: receiver_ty.clone(),
+ receiver: receiver_ty,
name: method_name.clone(),
- field_with_same_name: field_with_same_name_exists.clone(),
- assoc_func_with_same_name,
+ field_with_same_name: field_with_same_name_exists,
+ assoc_func_with_same_name: assoc_func_with_same_name.map(|it| it.def_id),
});
let recovered = match assoc_func_with_same_name {
- Some(f) => {
- let substs = self.substs_for_method_call(tgt_expr, f.into(), generic_args);
- let f = self
- .db
- .value_ty(f.into())
- .expect("we have a function def")
- .substitute(Interner, &substs);
- let sig = f.callable_sig(self.db).expect("we have a function def");
- Some((f, sig, true))
- }
+ Some(it) => Some((
+ Ty::new_fn_def(
+ self.interner(),
+ CallableDefId::FunctionId(it.def_id).into(),
+ it.args,
+ ),
+ it.sig,
+ true,
+ )),
None => field_with_same_name_exists.and_then(|field_ty| {
- let callable_sig = field_ty.callable_sig(self.db)?;
- Some((field_ty, callable_sig, false))
+ let callable_sig = field_ty.callable_sig(self.interner())?;
+ Some((field_ty, callable_sig.skip_binder(), false))
}),
};
match recovered {
@@ -2031,13 +1903,8 @@ impl<'db> InferenceContext<'db> {
tgt_expr,
args,
callee_ty,
- &sig.params()
- .get(strip_first as usize..)
- .unwrap_or(&[])
- .iter()
- .map(|param| param.to_nextsolver(self.table.interner))
- .collect::<Vec<_>>(),
- sig.ret().to_nextsolver(self.table.interner),
+ sig.inputs_and_output.inputs().get(strip_first as usize..).unwrap_or(&[]),
+ sig.output(),
&[],
true,
expected,
@@ -2057,41 +1924,20 @@ impl<'db> InferenceContext<'db> {
&mut self,
tgt_expr: ExprId,
args: &[ExprId],
- method_ty: Binders<Ty>,
- substs: Substitution,
- receiver_ty: Ty,
- expected: &Expectation,
- ) -> Ty {
- let method_ty = method_ty.substitute(Interner, &substs);
- self.register_obligations_for_call(&method_ty);
- let interner = self.table.interner;
- let ((formal_receiver_ty, param_tys), ret_ty, is_varargs) =
- match method_ty.callable_sig(self.db) {
- Some(sig) => (
- if !sig.params().is_empty() {
- (
- sig.params()[0].to_nextsolver(interner),
- sig.params()[1..]
- .iter()
- .map(|param| param.to_nextsolver(interner))
- .collect(),
- )
- } else {
- (crate::next_solver::Ty::new_error(interner, ErrorGuaranteed), Vec::new())
- },
- sig.ret().to_nextsolver(interner),
- sig.is_varargs,
- ),
- None => {
- let formal_receiver_ty = self.table.next_ty_var();
- let ret_ty = self.table.next_ty_var();
- ((formal_receiver_ty, Vec::new()), ret_ty, true)
- }
- };
- self.table.unify_ns(formal_receiver_ty, receiver_ty.to_nextsolver(interner));
+ sig: FnSig<'db>,
+ receiver_ty: Ty<'db>,
+ expected: &Expectation<'db>,
+ ) -> Ty<'db> {
+ let (formal_receiver_ty, param_tys) = if !sig.inputs_and_output.inputs().is_empty() {
+ (sig.inputs_and_output.as_slice()[0], &sig.inputs_and_output.inputs()[1..])
+ } else {
+ (self.types.error, &[] as _)
+ };
+ let ret_ty = sig.output();
+ self.table.unify(formal_receiver_ty, receiver_ty);
- self.check_call_arguments(tgt_expr, &param_tys, ret_ty, expected, args, &[], is_varargs);
- self.table.normalize_associated_types_in_ns(ret_ty).to_chalk(interner)
+ self.check_call_arguments(tgt_expr, param_tys, ret_ty, expected, args, &[], sig.c_variadic);
+ ret_ty
}
/// Generic function that factors out common logic from function calls,
@@ -2100,18 +1946,16 @@ impl<'db> InferenceContext<'db> {
&mut self,
call_expr: ExprId,
// Types (as defined in the *signature* of the target function)
- formal_input_tys: &[crate::next_solver::Ty<'db>],
- formal_output: crate::next_solver::Ty<'db>,
+ formal_input_tys: &[Ty<'db>],
+ formal_output: Ty<'db>,
// Expected output from the parent expression or statement
- expectation: &Expectation,
+ expectation: &Expectation<'db>,
// The expressions for each provided argument
provided_args: &[ExprId],
skip_indices: &[u32],
// Whether the function is variadic, for example when imported from C
c_variadic: bool,
) {
- let interner = self.table.interner;
-
// First, let's unify the formal method signature with the expectation eagerly.
// We use this to guide coercion inference; it's output is "fudged" which means
// any remaining type variables are assigned to new, unrelated variables. This
@@ -2130,14 +1974,9 @@ impl<'db> InferenceContext<'db> {
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = ObligationCause::new();
- ocx.sup(
- &origin,
- self.table.param_env,
- expected_output.to_nextsolver(interner),
- formal_output,
- )?;
- if !ocx.select_where_possible().is_empty() {
- return Err(crate::next_solver::TypeError::Mismatch);
+ ocx.sup(&origin, self.table.trait_env.env, expected_output, formal_output)?;
+ if !ocx.try_evaluate_obligations().is_empty() {
+ return Err(TypeError::Mismatch);
}
// Record all the argument types, with the args
@@ -2185,9 +2024,9 @@ impl<'db> InferenceContext<'db> {
// We introduce a helper function to demand that a given argument satisfy a given input
// This is more complicated than just checking type equality, as arguments could be coerced
// This version writes those types back so further type checking uses the narrowed types
- let demand_compatible = |this: &mut InferenceContext<'db>, idx| {
- let formal_input_ty: crate::next_solver::Ty<'db> = formal_input_tys[idx];
- let expected_input_ty: crate::next_solver::Ty<'db> = expected_input_tys[idx];
+ let demand_compatible = |this: &mut InferenceContext<'_, 'db>, idx| {
+ let formal_input_ty: Ty<'db> = formal_input_tys[idx];
+ let expected_input_ty: Ty<'db> = expected_input_tys[idx];
let provided_arg = provided_args[idx];
debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
@@ -2195,39 +2034,27 @@ impl<'db> InferenceContext<'db> {
// We're on the happy path here, so we'll do a more involved check and write back types
// To check compatibility, we'll do 3 things:
// 1. Unify the provided argument with the expected type
- let expectation = Expectation::rvalue_hint(this, expected_input_ty.to_chalk(interner));
+ let expectation = Expectation::rvalue_hint(this, expected_input_ty);
- let checked_ty = this
- .infer_expr_inner(provided_arg, &expectation, ExprIsRead::Yes)
- .to_nextsolver(interner);
+ let checked_ty = this.infer_expr_inner(provided_arg, &expectation, ExprIsRead::Yes);
// 2. Coerce to the most detailed type that could be coerced
// to, which is `expected_ty` if `rvalue_hint` returns an
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
- let coerced_ty = expectation
- .only_has_type(&mut this.table)
- .map(|it| it.to_nextsolver(interner))
- .unwrap_or(formal_input_ty);
+ let coerced_ty = expectation.only_has_type(&mut this.table).unwrap_or(formal_input_ty);
// Cause selection errors caused by resolving a single argument to point at the
// argument and not the call. This lets us customize the span pointed to in the
// fulfillment error to be more accurate.
let coerced_ty = this.table.resolve_vars_with_obligations(coerced_ty);
- let coerce_never = if this
- .expr_guaranteed_to_constitute_read_for_never(provided_arg, ExprIsRead::Yes)
- {
- CoerceNever::Yes
- } else {
- CoerceNever::No
- };
let coerce_error = this
.coerce(
provided_arg.into(),
checked_ty,
coerced_ty,
AllowTwoPhase::Yes,
- coerce_never,
+ ExprIsRead::Yes,
)
.err();
if coerce_error.is_some() {
@@ -2239,12 +2066,12 @@ impl<'db> InferenceContext<'db> {
let formal_ty_error = this
.table
.infer_ctxt
- .at(&ObligationCause::new(), this.table.param_env)
- .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty);
+ .at(&ObligationCause::new(), this.table.trait_env.env)
+ .eq(formal_input_ty, coerced_ty);
// If neither check failed, the types are compatible
match formal_ty_error {
- Ok(crate::next_solver::infer::InferOk { obligations, value: () }) => {
+ Ok(InferOk { obligations, value: () }) => {
this.table.register_predicates(obligations);
Ok(())
}
@@ -2298,13 +2125,10 @@ impl<'db> InferenceContext<'db> {
&& args_count_matches
{
// Don't report type mismatches if there is a mismatch in args count.
- self.result.type_mismatches.insert(
- (*arg).into(),
- TypeMismatch {
- expected: expected.to_chalk(interner),
- actual: found.to_chalk(interner),
- },
- );
+ self.result
+ .type_mismatches
+ .get_or_insert_default()
+ .insert((*arg).into(), TypeMismatch { expected, actual: found });
}
}
}
@@ -2312,181 +2136,35 @@ impl<'db> InferenceContext<'db> {
if !args_count_matches {}
}
- fn substs_for_method_call(
- &mut self,
- expr: ExprId,
- def: GenericDefId,
- generic_args: Option<&GenericArgs>,
- ) -> Substitution {
- struct LowererCtx<'a, 'b> {
- ctx: &'a mut InferenceContext<'b>,
- expr: ExprId,
- }
-
- impl GenericArgsLowerer for LowererCtx<'_, '_> {
- fn report_len_mismatch(
- &mut self,
- def: GenericDefId,
- provided_count: u32,
- expected_count: u32,
- kind: IncorrectGenericsLenKind,
- ) {
- self.ctx.push_diagnostic(InferenceDiagnostic::MethodCallIncorrectGenericsLen {
- expr: self.expr,
- provided_count,
- expected_count,
- kind,
- def,
- });
- }
-
- fn report_arg_mismatch(
- &mut self,
- param_id: GenericParamId,
- arg_idx: u32,
- has_self_arg: bool,
- ) {
- self.ctx.push_diagnostic(InferenceDiagnostic::MethodCallIncorrectGenericsOrder {
- expr: self.expr,
- param_id,
- arg_idx,
- has_self_arg,
- });
- }
-
- fn provided_kind(
- &mut self,
- param_id: GenericParamId,
- param: GenericParamDataRef<'_>,
- arg: &GenericArg,
- ) -> crate::GenericArg {
- match (param, arg) {
- (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => {
- self.ctx.make_body_lifetime(*lifetime).cast(Interner)
- }
- (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => {
- self.ctx.make_body_ty(*type_ref).cast(Interner)
- }
- (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => {
- let GenericParamId::ConstParamId(const_id) = param_id else {
- unreachable!("non-const param ID for const param");
- };
- let const_ty = self.ctx.db.const_param_ty(const_id);
- self.ctx.make_body_const(*konst, const_ty).cast(Interner)
- }
- _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"),
- }
- }
-
- fn provided_type_like_const(
- &mut self,
- const_ty: Ty,
- arg: TypeLikeConst<'_>,
- ) -> crate::Const {
- match arg {
- TypeLikeConst::Path(path) => self.ctx.make_path_as_body_const(path, const_ty),
- TypeLikeConst::Infer => self.ctx.table.new_const_var(const_ty),
- }
- }
-
- fn inferred_kind(
- &mut self,
- _def: GenericDefId,
- param_id: GenericParamId,
- _param: GenericParamDataRef<'_>,
- _infer_args: bool,
- _preceding_args: &[crate::GenericArg],
- ) -> crate::GenericArg {
- // Always create an inference var, even when `infer_args == false`. This helps with diagnostics,
- // and I think it's also required in the presence of `impl Trait` (that must be inferred).
- match param_id {
- GenericParamId::TypeParamId(_) => self.ctx.table.new_type_var().cast(Interner),
- GenericParamId::ConstParamId(const_id) => self
- .ctx
- .table
- .new_const_var(self.ctx.db.const_param_ty(const_id))
- .cast(Interner),
- GenericParamId::LifetimeParamId(_) => {
- self.ctx.table.new_lifetime_var().cast(Interner)
- }
- }
- }
-
- fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg {
- match param_id {
- GenericParamId::TypeParamId(_) => self.ctx.table.new_type_var().cast(Interner),
- GenericParamId::ConstParamId(const_id) => self
- .ctx
- .table
- .new_const_var(self.ctx.db.const_param_ty(const_id))
- .cast(Interner),
- GenericParamId::LifetimeParamId(_) => {
- self.ctx.table.new_lifetime_var().cast(Interner)
- }
- }
- }
-
- fn report_elided_lifetimes_in_path(
- &mut self,
- _def: GenericDefId,
- _expected_count: u32,
- _hard_error: bool,
- ) {
- unreachable!("we set `LifetimeElisionKind::Infer`")
- }
-
- fn report_elision_failure(&mut self, _def: GenericDefId, _expected_count: u32) {
- unreachable!("we set `LifetimeElisionKind::Infer`")
- }
-
- fn report_missing_lifetime(&mut self, _def: GenericDefId, _expected_count: u32) {
- unreachable!("we set `LifetimeElisionKind::Infer`")
- }
- }
-
- substs_from_args_and_bindings(
- self.db,
- self.body,
- generic_args,
- def,
- true,
- LifetimeElisionKind::Infer,
- false,
- None,
- &mut LowererCtx { ctx: self, expr },
- )
- }
-
- fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
- let callable_ty = self.table.structurally_resolve_type(callable_ty);
- if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) {
- let def: CallableDefId = from_chalk(self.db, *fn_def);
- let generic_predicates =
- self.db.generic_predicates(GenericDefId::from_callable(self.db, def));
- for predicate in generic_predicates.iter() {
- let (predicate, binders) = predicate
- .clone()
- .substitute(Interner, parameters)
- .into_value_and_skipped_binders();
- always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
- self.push_obligation(predicate.cast(Interner));
- }
+ 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.trait_env.env;
+ self.table.register_predicates(clauses_as_obligations(
+ generic_predicates.iter_instantiated_copied(self.interner(), parameters.as_slice()),
+ ObligationCause::new(),
+ param_env,
+ ));
// add obligation for trait implementation, if this is a trait method
- match def {
+ 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 = Substitution::from_iter(
- Interner,
- // The generic parameters for the trait come after those for the
- // function.
- &parameters.as_slice(Interner)[..trait_params_len],
- );
- self.push_obligation(
- TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
- .cast(Interner),
+ let substs = GenericArgs::new_from_iter(
+ self.interner(),
+ parameters.as_slice()[..trait_params_len].iter().copied(),
);
+ self.table.register_predicate(Obligation::new(
+ self.interner(),
+ ObligationCause::new(),
+ self.table.trait_env.env,
+ TraitRef::new(self.interner(), trait_.into(), substs),
+ ));
}
}
CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
@@ -2495,11 +2173,10 @@ impl<'db> InferenceContext<'db> {
}
/// Returns the argument indices to skip.
- fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Box<[u32]> {
- let (func, subst) = match callee.kind(Interner) {
- TyKind::FnDef(fn_id, subst) => {
- let callable = CallableDefId::from_chalk(self.db, *fn_id);
- let func = match callable {
+ fn check_legacy_const_generics(&mut self, callee: Ty<'db>, args: &[ExprId]) -> Box<[u32]> {
+ let (func, _subst) = match callee.kind() {
+ TyKind::FnDef(callable, subst) => {
+ let func = match callable.0 {
CallableDefId::FunctionId(f) => f,
_ => return Default::default(),
};
@@ -2509,9 +2186,11 @@ impl<'db> InferenceContext<'db> {
};
let data = self.db.function_signature(func);
- let Some(legacy_const_generics_indices) = &data.legacy_const_generics_indices else {
+ let Some(legacy_const_generics_indices) = data.legacy_const_generics_indices(self.db, func)
+ else {
return Default::default();
};
+ let mut legacy_const_generics_indices = Box::<[u32]>::from(legacy_const_generics_indices);
// only use legacy const generics if the param count matches with them
if data.params.len() + legacy_const_generics_indices.len() != args.len() {
@@ -2520,171 +2199,36 @@ impl<'db> InferenceContext<'db> {
} else {
// there are more parameters than there should be without legacy
// const params; use them
- let mut indices = legacy_const_generics_indices.as_ref().clone();
- indices.sort();
- return indices;
+ legacy_const_generics_indices.sort_unstable();
+ return legacy_const_generics_indices;
}
}
// check legacy const parameters
- for (subst_idx, arg_idx) in legacy_const_generics_indices.iter().copied().enumerate() {
- let arg = match subst.at(Interner, subst_idx).constant(Interner) {
- Some(c) => c,
- None => continue, // not a const parameter?
- };
+ for arg_idx in legacy_const_generics_indices.iter().copied() {
if arg_idx >= args.len() as u32 {
continue;
}
- let _ty = arg.data(Interner).ty.clone();
let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly
self.infer_expr(args[arg_idx as usize], &expected, ExprIsRead::Yes);
// FIXME: evaluate and unify with the const
}
- let mut indices = legacy_const_generics_indices.as_ref().clone();
- indices.sort();
- indices
- }
-
- /// Dereferences a single level of immutable referencing.
- fn deref_ty_if_possible(&mut self, ty: &Ty) -> Ty {
- let ty = self.table.structurally_resolve_type(ty);
- match ty.kind(Interner) {
- TyKind::Ref(Mutability::Not, _, inner) => self.table.structurally_resolve_type(inner),
- _ => ty,
- }
- }
-
- /// Enforces expectations on lhs type and rhs type depending on the operator and returns the
- /// output type of the binary op.
- fn enforce_builtin_binop_types(&mut self, lhs: &Ty, rhs: &Ty, op: BinaryOp) -> Ty {
- // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work (See rust-lang/rust#57447).
- let lhs = self.deref_ty_if_possible(lhs);
- let rhs = self.deref_ty_if_possible(rhs);
-
- let (op, is_assign) = match op {
- BinaryOp::Assignment { op: Some(inner) } => (BinaryOp::ArithOp(inner), true),
- _ => (op, false),
- };
-
- let output_ty = match op {
- BinaryOp::LogicOp(_) => {
- let bool_ = self.result.standard_types.bool_.clone();
- self.unify(&lhs, &bool_);
- self.unify(&rhs, &bool_);
- bool_
- }
-
- BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
- // result type is same as LHS always
- lhs
- }
-
- BinaryOp::ArithOp(_) => {
- // LHS, RHS, and result will have the same type
- self.unify(&lhs, &rhs);
- lhs
- }
-
- BinaryOp::CmpOp(_) => {
- // LHS and RHS will have the same type
- self.unify(&lhs, &rhs);
- self.result.standard_types.bool_.clone()
- }
-
- BinaryOp::Assignment { op: None } => {
- stdx::never!("Simple assignment operator is not binary op.");
- lhs
- }
-
- BinaryOp::Assignment { .. } => unreachable!("handled above"),
- };
-
- if is_assign { self.result.standard_types.unit.clone() } else { output_ty }
- }
-
- fn is_builtin_binop(&mut self, lhs: &Ty, rhs: &Ty, op: BinaryOp) -> bool {
- // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work (See rust-lang/rust#57447).
- let lhs = self.deref_ty_if_possible(lhs);
- let rhs = self.deref_ty_if_possible(rhs);
-
- let op = match op {
- BinaryOp::Assignment { op: Some(inner) } => BinaryOp::ArithOp(inner),
- _ => op,
- };
-
- match op {
- BinaryOp::LogicOp(_) => true,
-
- BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
- lhs.is_integral() && rhs.is_integral()
- }
-
- BinaryOp::ArithOp(
- ArithOp::Add | ArithOp::Sub | ArithOp::Mul | ArithOp::Div | ArithOp::Rem,
- ) => {
- lhs.is_integral() && rhs.is_integral()
- || lhs.is_floating_point() && rhs.is_floating_point()
- }
-
- BinaryOp::ArithOp(ArithOp::BitAnd | ArithOp::BitOr | ArithOp::BitXor) => {
- lhs.is_integral() && rhs.is_integral()
- || lhs.is_floating_point() && rhs.is_floating_point()
- || matches!(
- (lhs.kind(Interner), rhs.kind(Interner)),
- (TyKind::Scalar(Scalar::Bool), TyKind::Scalar(Scalar::Bool))
- )
- }
-
- BinaryOp::CmpOp(_) => {
- let is_scalar = |kind| {
- matches!(
- kind,
- &TyKind::Scalar(_)
- | TyKind::FnDef(..)
- | TyKind::Function(_)
- | TyKind::Raw(..)
- | TyKind::InferenceVar(
- _,
- TyVariableKind::Integer | TyVariableKind::Float
- )
- )
- };
- is_scalar(lhs.kind(Interner)) && is_scalar(rhs.kind(Interner))
- }
-
- BinaryOp::Assignment { op: None } => {
- stdx::never!("Simple assignment operator is not binary op.");
- false
- }
-
- BinaryOp::Assignment { .. } => unreachable!("handled above"),
- }
+ legacy_const_generics_indices.sort_unstable();
+ legacy_const_generics_indices
}
pub(super) fn with_breakable_ctx<T>(
&mut self,
kind: BreakableKind,
- ty: Option<Ty>,
+ ty: Option<Ty<'db>>,
label: Option<LabelId>,
cb: impl FnOnce(&mut Self) -> T,
- ) -> (Option<Ty>, T) {
+ ) -> (Option<Ty<'db>>, T) {
self.breakables.push({
- BreakableContext {
- kind,
- may_break: false,
- coerce: ty.map(|ty| CoerceMany::new(ty.to_nextsolver(self.table.interner))),
- label,
- }
+ BreakableContext { kind, may_break: false, coerce: ty.map(CoerceMany::new), label }
});
let res = cb(self);
let ctx = self.breakables.pop().expect("breakable stack broken");
- (
- if ctx.may_break {
- ctx.coerce.map(|ctx| ctx.complete(self).to_chalk(self.table.interner))
- } else {
- None
- },
- res,
- )
+ (if ctx.may_break { ctx.coerce.map(|ctx| ctx.complete(self)) } else { None }, res)
}
}