fix: Always explicitly set trait ref self types when lowering

This commit is contained in:
Lukas Wirth 2024-09-06 14:04:57 +02:00
parent 70ee4e5545
commit 20f7ab5ab4
9 changed files with 80 additions and 64 deletions

View file

@ -1556,7 +1556,7 @@ fn builtin_derive_macro() {
Bar, Bar,
} }
#[derive(Clone)] #[derive(Clone)]
struct X(i32, Z, i64) struct X(i32, Z, i64);
#[derive(Clone)] #[derive(Clone)]
struct Y { struct Y {
field1: i32, field1: i32,
@ -1574,20 +1574,20 @@ fn builtin_derive_macro() {
); );
check_number( check_number(
r#" r#"
//- minicore: default, derive, builtin_impls //- minicore: default, derive, builtin_impls
#[derive(Default)] #[derive(Default)]
struct X(i32, Y, i64) struct X(i32, Y, i64);
#[derive(Default)] #[derive(Default)]
struct Y { struct Y {
field1: i32, field1: i32,
field2: u8, field2: u8,
} }
const GOAL: u8 = { const GOAL: u8 = {
let x = X::default(); let x = X::default();
x.1.field2 x.1.field2
}; };
"#, "#,
0, 0,
); );
} }
@ -2828,7 +2828,7 @@ fn type_error() {
y.0 y.0
}; };
"#, "#,
|e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))), |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::HasErrors)),
); );
} }

View file

@ -851,7 +851,7 @@ impl InferenceContext<'_> {
}; };
for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); *ty = self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
} }
TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner) TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)

View file

@ -247,8 +247,12 @@ impl InferenceContext<'_> {
&self.resolver, &self.resolver,
self.owner.into(), self.owner.into(),
); );
let trait_ref = let trait_ref = ctx.lower_trait_ref_from_resolved_path(
ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); trait_,
resolved_segment,
self.table.new_type_var(),
);
self.resolve_trait_assoc_item(trait_ref, segment, id) self.resolve_trait_assoc_item(trait_ref, segment, id)
} }
(def, _) => { (def, _) => {

View file

@ -516,8 +516,11 @@ impl<'a> TyLoweringContext<'a> {
TypeNs::TraitId(trait_) => { TypeNs::TraitId(trait_) => {
let ty = match remaining_segments.len() { let ty = match remaining_segments.len() {
1 => { 1 => {
let trait_ref = let trait_ref = self.lower_trait_ref_from_resolved_path(
self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); trait_,
resolved_segment,
TyKind::Error.intern(Interner),
);
let segment = remaining_segments.first().unwrap(); let segment = remaining_segments.first().unwrap();
let found = self let found = self
.db .db
@ -952,11 +955,17 @@ impl<'a> TyLoweringContext<'a> {
Substitution::from_iter(Interner, substs) Substitution::from_iter(Interner, substs)
} }
fn lower_trait_ref_from_path( pub(crate) fn lower_trait_ref_from_resolved_path(
&self, &self,
path: &Path, resolved: TraitId,
explicit_self_ty: Option<Ty>, segment: PathSegment<'_>,
) -> Option<TraitRef> { explicit_self_ty: Ty,
) -> TraitRef {
let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
}
fn lower_trait_ref_from_path(&self, path: &Path, explicit_self_ty: Ty) -> Option<TraitRef> {
let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? { let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? {
// FIXME(trait_alias): We need to handle trait alias here. // FIXME(trait_alias): We need to handle trait alias here.
TypeNs::TraitId(tr) => tr, TypeNs::TraitId(tr) => tr,
@ -966,21 +975,7 @@ impl<'a> TyLoweringContext<'a> {
Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
} }
pub(crate) fn lower_trait_ref_from_resolved_path( fn lower_trait_ref(&self, trait_ref: &HirTraitRef, explicit_self_ty: Ty) -> Option<TraitRef> {
&self,
resolved: TraitId,
segment: PathSegment<'_>,
explicit_self_ty: Option<Ty>,
) -> TraitRef {
let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
}
fn lower_trait_ref(
&self,
trait_ref: &HirTraitRef,
explicit_self_ty: Option<Ty>,
) -> Option<TraitRef> {
self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty) self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
} }
@ -988,9 +983,9 @@ impl<'a> TyLoweringContext<'a> {
&self, &self,
segment: PathSegment<'_>, segment: PathSegment<'_>,
resolved: TraitId, resolved: TraitId,
explicit_self_ty: Option<Ty>, explicit_self_ty: Ty,
) -> Substitution { ) -> Substitution {
self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty) self.substs_from_path_segment(segment, Some(resolved.into()), false, Some(explicit_self_ty))
} }
pub(crate) fn lower_where_predicate<'b>( pub(crate) fn lower_where_predicate<'b>(
@ -1041,7 +1036,7 @@ impl<'a> TyLoweringContext<'a> {
let mut trait_ref = None; let mut trait_ref = None;
let clause = match bound.as_ref() { let clause = match bound.as_ref() {
TypeBound::Path(path, TraitBoundModifier::None) => { TypeBound::Path(path, TraitBoundModifier::None) => {
trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); trait_ref = self.lower_trait_ref_from_path(path, self_ty);
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
} }
TypeBound::Path(path, TraitBoundModifier::Maybe) => { TypeBound::Path(path, TraitBoundModifier::Maybe) => {
@ -1053,7 +1048,7 @@ impl<'a> TyLoweringContext<'a> {
// `?Sized` has no of them. // `?Sized` has no of them.
// If we got another trait here ignore the bound completely. // If we got another trait here ignore the bound completely.
let trait_id = self let trait_id = self
.lower_trait_ref_from_path(path, Some(self_ty.clone())) .lower_trait_ref_from_path(path, self_ty.clone())
.map(|trait_ref| trait_ref.hir_trait_id()); .map(|trait_ref| trait_ref.hir_trait_id());
if trait_id == sized_trait { if trait_id == sized_trait {
self.unsized_types.borrow_mut().insert(self_ty); self.unsized_types.borrow_mut().insert(self_ty);
@ -1062,7 +1057,7 @@ impl<'a> TyLoweringContext<'a> {
} }
TypeBound::ForLifetime(_, path) => { TypeBound::ForLifetime(_, path) => {
// FIXME Don't silently drop the hrtb lifetimes here // FIXME Don't silently drop the hrtb lifetimes here
trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); trait_ref = self.lower_trait_ref_from_path(path, self_ty);
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
} }
TypeBound::Lifetime(l) => { TypeBound::Lifetime(l) => {
@ -2126,7 +2121,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
let target_trait = impl_data.target_trait.as_ref()?; let target_trait = impl_data.target_trait.as_ref()?;
Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?)) Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?))
} }
pub(crate) fn return_type_impl_traits( pub(crate) fn return_type_impl_traits(

View file

@ -421,9 +421,25 @@ impl MirEvalError {
} }
MirEvalError::MirLowerError(func, err) => { MirEvalError::MirLowerError(func, err) => {
let function_name = db.function_data(*func); let function_name = db.function_data(*func);
let self_ = match func.lookup(db.upcast()).container {
ItemContainerId::ImplId(impl_id) => Some({
let generics = crate::generics::generics(db.upcast(), impl_id.into());
let substs = generics.placeholder_subst(db);
db.impl_self_ty(impl_id)
.substitute(Interner, &substs)
.display(db, edition)
.to_string()
}),
ItemContainerId::TraitId(it) => {
Some(db.trait_data(it).name.display(db.upcast(), edition).to_string())
}
_ => None,
};
writeln!( writeln!(
f, f,
"MIR lowering for function `{}` ({:?}) failed due:", "MIR lowering for function `{}{}{}` ({:?}) failed due:",
self_.as_deref().unwrap_or_default(),
if self_.is_some() { "::" } else { "" },
function_name.name.display(db.upcast(), edition), function_name.name.display(db.upcast(), edition),
func func
)?; )?;

View file

@ -94,7 +94,8 @@ pub enum MirLowerError {
UnresolvedField, UnresolvedField,
UnsizedTemporary(Ty), UnsizedTemporary(Ty),
MissingFunctionDefinition(DefWithBodyId, ExprId), MissingFunctionDefinition(DefWithBodyId, ExprId),
TypeMismatch(Option<TypeMismatch>), TypeMismatch(TypeMismatch),
HasErrors,
/// This should never happen. Type mismatch should catch everything. /// This should never happen. Type mismatch should catch everything.
TypeError(&'static str), TypeError(&'static str),
NotSupported(String), NotSupported(String),
@ -179,15 +180,13 @@ impl MirLowerError {
body.pretty_print_expr(db.upcast(), *owner, *it, edition) body.pretty_print_expr(db.upcast(), *owner, *it, edition)
)?; )?;
} }
MirLowerError::TypeMismatch(e) => match e { MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?,
Some(e) => writeln!( MirLowerError::TypeMismatch(e) => writeln!(
f, f,
"Type mismatch: Expected {}, found {}", "Type mismatch: Expected {}, found {}",
e.expected.display(db, edition), e.expected.display(db, edition),
e.actual.display(db, edition), e.actual.display(db, edition),
)?, )?,
None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?,
},
MirLowerError::GenericArgNotProvided(id, subst) => { MirLowerError::GenericArgNotProvided(id, subst) => {
let parent = id.parent; let parent = id.parent;
let param = &db.generic_params(parent)[id.local_id]; let param = &db.generic_params(parent)[id.local_id];
@ -2184,7 +2183,7 @@ pub fn lower_to_mir(
root_expr: ExprId, root_expr: ExprId,
) -> Result<MirBody> { ) -> Result<MirBody> {
if infer.has_errors { if infer.has_errors {
return Err(MirLowerError::TypeMismatch(None)); return Err(MirLowerError::HasErrors);
} }
let mut ctx = MirLowerCtx::new(db, owner, body, infer); let mut ctx = MirLowerCtx::new(db, owner, body, infer);
// 0 is return local // 0 is return local

View file

@ -831,7 +831,7 @@ fn main() {
//- minicore: sized //- minicore: sized
fn main() { fn main() {
_ = ((), ()) as (); _ = ((), ()) as ();
//^^^^^^^^^^^^^^ error: non-primitive cast: `(_, _)` as `()` //^^^^^^^^^^^^^^ error: non-primitive cast: `((), ())` as `()`
} }
"#, "#,
); );

View file

@ -95,8 +95,10 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static {
fn test_crate(&self) -> CrateId { fn test_crate(&self) -> CrateId {
let crate_graph = self.crate_graph(); let crate_graph = self.crate_graph();
let mut it = crate_graph.iter(); let mut it = crate_graph.iter();
let res = it.next().unwrap(); let mut res = it.next().unwrap();
assert!(it.next().is_none()); while crate_graph[res].origin.is_lang() {
res = it.next().unwrap();
}
res res
} }
} }

View file

@ -171,7 +171,7 @@ pub mod default {
macro_rules! impl_default { macro_rules! impl_default {
($v:literal; $($t:ty)*) => { ($v:literal; $($t:ty)*) => {
$( $(
impl const Default for $t { impl Default for $t {
fn default() -> Self { fn default() -> Self {
$v $v
} }
@ -686,7 +686,7 @@ pub mod ops {
// endregion:fn // endregion:fn
// region:try // region:try
mod try_ { mod try_ {
use super::super::convert::Infallible; use crate::convert::Infallible;
pub enum ControlFlow<B, C = ()> { pub enum ControlFlow<B, C = ()> {
#[lang = "Continue"] #[lang = "Continue"]
@ -756,7 +756,7 @@ pub mod ops {
// endregion:option // endregion:option
// region:result // region:result
// region:from // region:from
use super::super::convert::From; use crate::convert::From;
impl<T, E> Try for Result<T, E> { impl<T, E> Try for Result<T, E> {
type Output = T; type Output = T;
@ -777,7 +777,7 @@ pub mod ops {
impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> { impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {
fn from_residual(residual: Result<Infallible, E>) -> Self { fn from_residual(residual: Result<Infallible, E>) -> Self {
match residual { match residual {
Err(e) => Err(From::from(e)), Err(e) => Err(F::from(e)),
Ok(_) => loop {}, Ok(_) => loop {},
} }
} }