This commit is contained in:
Lukas Wirth 2023-03-29 23:33:39 +02:00
parent e797479651
commit 251b3a47af
8 changed files with 98 additions and 108 deletions

View File

@ -3,8 +3,6 @@
//! reference to a type with the field `bar`. This is an approximation of the //! reference to a type with the field `bar`. This is an approximation of the
//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs). //! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
use std::sync::Arc;
use chalk_ir::cast::Cast; use chalk_ir::cast::Cast;
use hir_def::{ use hir_def::{
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
@ -13,10 +11,7 @@ use hir_def::{
use hir_expand::name::name; use hir_expand::name::name;
use limit::Limit; use limit::Limit;
use crate::{ use crate::{infer::unify::InferenceTable, Goal, Interner, ProjectionTyExt, Ty, TyBuilder, TyKind};
db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt,
TraitEnvironment, Ty, TyBuilder, TyKind,
};
static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10); static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
@ -27,15 +22,15 @@ pub(crate) enum AutoderefKind {
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Autoderef<'a, 'db> { pub struct Autoderef<'a, 'db> {
pub(crate) table: &'a mut InferenceTable<'db>, pub table: &'a mut InferenceTable<'db>,
ty: Ty, ty: Ty,
at_start: bool, at_start: bool,
steps: Vec<(AutoderefKind, Ty)>, steps: Vec<(AutoderefKind, Ty)>,
} }
impl<'a, 'db> Autoderef<'a, 'db> { impl<'a, 'db> Autoderef<'a, 'db> {
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self { pub fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self {
let ty = table.resolve_ty_shallow(&ty); let ty = table.resolve_ty_shallow(&ty);
Autoderef { table, ty, at_start: true, steps: Vec::new() } Autoderef { table, ty, at_start: true, steps: Vec::new() }
} }
@ -86,22 +81,6 @@ pub(crate) fn autoderef_step(
} }
} }
// FIXME: replace uses of this with Autoderef above
pub fn autoderef(
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
ty: Canonical<Ty>,
) -> impl Iterator<Item = Canonical<Ty>> + '_ {
let mut table = InferenceTable::new(db, env);
let ty = table.instantiate_canonical(ty);
let mut autoderef = Autoderef::new(&mut table, ty);
let mut v = Vec::new();
while let Some((ty, _steps)) = autoderef.next() {
v.push(autoderef.table.canonicalize(ty).value);
}
v.into_iter()
}
pub(crate) fn builtin_deref<'ty>( pub(crate) fn builtin_deref<'ty>(
table: &mut InferenceTable<'_>, table: &mut InferenceTable<'_>,
ty: &'ty Ty, ty: &'ty Ty,

View File

@ -28,11 +28,12 @@ use crate::{
infer::{ infer::{
coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind, coerce::CoerceMany, find_continuable, pat::contains_explicit_ref_binding, BreakableKind,
}, },
lang_items::lang_items_for_bin_op,
lower::{ lower::{
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
}, },
mapping::{from_chalk, ToChalk}, mapping::{from_chalk, ToChalk},
method_resolution::{self, lang_items_for_bin_op, VisibleFromModule}, method_resolution::{self, VisibleFromModule},
primitive::{self, UintTy}, primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id, static_lifetime, to_chalk_trait_id,
traits::FnTrait, traits::FnTrait,
@ -792,7 +793,7 @@ impl<'a> InferenceContext<'a> {
let canonicalized = self.canonicalize(base_ty.clone()); let canonicalized = self.canonicalize(base_ty.clone());
let receiver_adjustments = method_resolution::resolve_indexing_op( let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db, self.db,
self.table.trait_env.clone(), &mut self.table,
canonicalized.value, canonicalized.value,
index_trait, index_trait,
); );

View File

@ -32,11 +32,11 @@ impl<'a> InferenceContext<'a> {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Canonicalized<T> pub struct Canonicalized<T>
where where
T: HasInterner<Interner = Interner>, T: HasInterner<Interner = Interner>,
{ {
pub(crate) value: Canonical<T>, pub value: Canonical<T>,
free_vars: Vec<GenericArg>, free_vars: Vec<GenericArg>,
} }
@ -140,7 +140,7 @@ bitflags::bitflags! {
type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>; type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct InferenceTable<'a> { pub struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>, pub(crate) trait_env: Arc<TraitEnvironment>,
var_unification_table: ChalkInferenceTable, var_unification_table: ChalkInferenceTable,
@ -155,7 +155,7 @@ pub(crate) struct InferenceTableSnapshot {
} }
impl<'a> InferenceTable<'a> { impl<'a> InferenceTable<'a> {
pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self { pub fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
InferenceTable { InferenceTable {
db, db,
trait_env, trait_env,
@ -204,7 +204,7 @@ impl<'a> InferenceTable<'a> {
.intern(Interner) .intern(Interner)
} }
pub(crate) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>( pub fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
&mut self, &mut self,
t: T, t: T,
) -> Canonicalized<T> ) -> Canonicalized<T>
@ -320,7 +320,7 @@ impl<'a> InferenceTable<'a> {
) )
} }
pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T pub fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T
where where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + std::fmt::Debug, T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + std::fmt::Debug,
{ {

View File

@ -1,6 +1,7 @@
//! Functions to detect special lang items //! Functions to detect special lang items
use hir_def::{lang_item::LangItem, AdtId, HasModule}; use hir_def::{lang_item::LangItem, AdtId, HasModule};
use hir_expand::name::Name;
use crate::db::HirDatabase; use crate::db::HirDatabase;
@ -17,3 +18,52 @@ pub fn is_unsafe_cell(adt: AdtId, db: &dyn HirDatabase) -> bool {
db.lang_item(krate, LangItem::UnsafeCell).and_then(|it| it.as_struct()).map(AdtId::from); db.lang_item(krate, LangItem::UnsafeCell).and_then(|it| it.as_struct()).map(AdtId::from);
Some(adt) == box_adt Some(adt) == box_adt
} }
pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> {
use hir_expand::name;
use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
Some(match op {
BinaryOp::LogicOp(_) => return None,
BinaryOp::ArithOp(aop) => match aop {
ArithOp::Add => (name![add], LangItem::Add),
ArithOp::Mul => (name![mul], LangItem::Mul),
ArithOp::Sub => (name![sub], LangItem::Sub),
ArithOp::Div => (name![div], LangItem::Div),
ArithOp::Rem => (name![rem], LangItem::Rem),
ArithOp::Shl => (name![shl], LangItem::Shl),
ArithOp::Shr => (name![shr], LangItem::Shr),
ArithOp::BitXor => (name![bitxor], LangItem::BitXor),
ArithOp::BitOr => (name![bitor], LangItem::BitOr),
ArithOp::BitAnd => (name![bitand], LangItem::BitAnd),
},
BinaryOp::Assignment { op: Some(aop) } => match aop {
ArithOp::Add => (name![add_assign], LangItem::AddAssign),
ArithOp::Mul => (name![mul_assign], LangItem::MulAssign),
ArithOp::Sub => (name![sub_assign], LangItem::SubAssign),
ArithOp::Div => (name![div_assign], LangItem::DivAssign),
ArithOp::Rem => (name![rem_assign], LangItem::RemAssign),
ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign),
ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign),
ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign),
ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign),
ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign),
},
BinaryOp::CmpOp(cop) => match cop {
CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq),
CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq),
CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
(name![le], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
(name![lt], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
(name![ge], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
(name![gt], LangItem::PartialOrd)
}
},
BinaryOp::Assignment { op: None } => return None,
})
}

View File

@ -7,12 +7,9 @@ macro_rules! eprintln {
($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
} }
mod autoderef;
mod builder; mod builder;
mod chalk_db; mod chalk_db;
mod chalk_ext; mod chalk_ext;
pub mod consteval;
pub mod mir;
mod infer; mod infer;
mod inhabitedness; mod inhabitedness;
mod interner; mod interner;
@ -20,14 +17,18 @@ mod lower;
mod mapping; mod mapping;
mod tls; mod tls;
mod utils; mod utils;
pub mod autoderef;
pub mod consteval;
pub mod db; pub mod db;
pub mod diagnostics; pub mod diagnostics;
pub mod display; pub mod display;
pub mod lang_items;
pub mod layout;
pub mod method_resolution; pub mod method_resolution;
pub mod mir;
pub mod primitive; pub mod primitive;
pub mod traits; pub mod traits;
pub mod layout;
pub mod lang_items;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -51,16 +52,14 @@ use rustc_hash::FxHashSet;
use traits::FnTrait; use traits::FnTrait;
use utils::Generics; use utils::Generics;
use crate::{ use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics,
};
pub use autoderef::autoderef; pub use autoderef::Autoderef;
pub use builder::{ParamKind, TyBuilder}; pub use builder::{ParamKind, TyBuilder};
pub use chalk_ext::*; pub use chalk_ext::*;
pub use infer::{ pub use infer::{
could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, could_coerce, could_unify, unify::InferenceTable, Adjust, Adjustment, AutoBorrow, BindingMode,
InferenceResult, OverloadedDeref, PointerCast, InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast,
}; };
pub use interner::Interner; pub use interner::Interner;
pub use lower::{ pub use lower::{

View File

@ -7,9 +7,8 @@ use std::{ops::ControlFlow, sync::Arc};
use base_db::{CrateId, Edition}; use base_db::{CrateId, Edition};
use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause}; use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
use hir_def::{ use hir_def::{
data::ImplData, item_scope::ItemScope, lang_item::LangItem, nameres::DefMap, AssocItemId, data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
ModuleId, TraitId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -451,55 +450,6 @@ pub fn def_crates(
} }
} }
pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> {
use hir_expand::name;
use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
Some(match op {
BinaryOp::LogicOp(_) => return None,
BinaryOp::ArithOp(aop) => match aop {
ArithOp::Add => (name![add], LangItem::Add),
ArithOp::Mul => (name![mul], LangItem::Mul),
ArithOp::Sub => (name![sub], LangItem::Sub),
ArithOp::Div => (name![div], LangItem::Div),
ArithOp::Rem => (name![rem], LangItem::Rem),
ArithOp::Shl => (name![shl], LangItem::Shl),
ArithOp::Shr => (name![shr], LangItem::Shr),
ArithOp::BitXor => (name![bitxor], LangItem::BitXor),
ArithOp::BitOr => (name![bitor], LangItem::BitOr),
ArithOp::BitAnd => (name![bitand], LangItem::BitAnd),
},
BinaryOp::Assignment { op: Some(aop) } => match aop {
ArithOp::Add => (name![add_assign], LangItem::AddAssign),
ArithOp::Mul => (name![mul_assign], LangItem::MulAssign),
ArithOp::Sub => (name![sub_assign], LangItem::SubAssign),
ArithOp::Div => (name![div_assign], LangItem::DivAssign),
ArithOp::Rem => (name![rem_assign], LangItem::RemAssign),
ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign),
ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign),
ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign),
ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign),
ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign),
},
BinaryOp::CmpOp(cop) => match cop {
CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq),
CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq),
CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
(name![le], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
(name![lt], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
(name![ge], LangItem::PartialOrd)
}
CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
(name![gt], LangItem::PartialOrd)
}
},
BinaryOp::Assignment { op: None } => return None,
})
}
/// Look up the method with the given name. /// Look up the method with the given name.
pub(crate) fn lookup_method( pub(crate) fn lookup_method(
db: &dyn HirDatabase, db: &dyn HirDatabase,
@ -1310,16 +1260,18 @@ fn iterate_inherent_methods(
/// Returns the receiver type for the index trait call. /// Returns the receiver type for the index trait call.
pub fn resolve_indexing_op( pub fn resolve_indexing_op(
db: &dyn HirDatabase, db: &dyn HirDatabase,
env: Arc<TraitEnvironment>, table: &mut InferenceTable<'_>,
ty: Canonical<Ty>, ty: Canonical<Ty>,
index_trait: TraitId, index_trait: TraitId,
) -> Option<ReceiverAdjustments> { ) -> Option<ReceiverAdjustments> {
let mut table = InferenceTable::new(db, env.clone());
let ty = table.instantiate_canonical(ty); let ty = table.instantiate_canonical(ty);
let deref_chain = autoderef_method_receiver(&mut table, ty); let deref_chain = autoderef_method_receiver(table, ty);
for (ty, adj) in deref_chain { for (ty, adj) in deref_chain {
let goal = generic_implements_goal(db, env.clone(), index_trait, &ty); let goal = generic_implements_goal(db, table.trait_env.clone(), index_trait, &ty);
if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_some() { if db
.trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner))
.is_some()
{
return Some(adj); return Some(adj);
} }
} }

View File

@ -57,7 +57,7 @@ use hir_def::{
}; };
use hir_expand::{name::name, MacroCallKind}; use hir_expand::{name::name, MacroCallKind};
use hir_ty::{ use hir_ty::{
all_super_traits, autoderef, all_super_traits,
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
diagnostics::BodyValidationDiagnostic, diagnostics::BodyValidationDiagnostic,
display::HexifiedConst, display::HexifiedConst,
@ -66,9 +66,10 @@ use hir_ty::{
mir::{self, interpret_mir}, mir::{self, interpret_mir},
primitive::UintTy, primitive::UintTy,
traits::FnTrait, traits::FnTrait,
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, AliasTy, Autoderef, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, GenericArgData, InferenceTable, Interner, ParamKind, QuantifiedWhereClause, Scalar,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind,
WhereClause,
}; };
use itertools::Itertools; use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind; use nameres::diagnostics::DefDiagnosticKind;
@ -3517,8 +3518,15 @@ impl Type {
fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a { fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
// There should be no inference vars in types passed here // There should be no inference vars in types passed here
let canonical = hir_ty::replace_errors_with_variables(&self.ty); let canonical = hir_ty::replace_errors_with_variables(&self.ty);
let environment = self.env.clone();
autoderef(db, environment, canonical).map(|canonical| canonical.value) let mut table = InferenceTable::new(db, self.env.clone());
let ty = table.instantiate_canonical(canonical);
let mut autoderef = Autoderef::new(&mut table, ty);
let mut v = Vec::new();
while let Some((ty, _steps)) = autoderef.next() {
v.push(autoderef.table.canonicalize(ty).value);
}
v.into_iter().map(|canonical| canonical.value)
} }
// This would be nicer if it just returned an iterator, but that runs into // This would be nicer if it just returned an iterator, but that runs into

View File

@ -39,7 +39,8 @@ use hir_ty::{
record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
UnsafeExpr, UnsafeExpr,
}, },
method_resolution::{self, lang_items_for_bin_op}, lang_items::lang_items_for_bin_op,
method_resolution::{self},
Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
}; };
use itertools::Itertools; use itertools::Itertools;