Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: consider outer binders when folding captured items' type #14971

Merged
merged 3 commits into from Jun 4, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/hir-ty/src/infer.rs
Expand Up @@ -367,6 +367,10 @@ pub enum PointerCast {
}

/// The result of type inference: A mapping from expressions and patterns to types.
///
/// When you add a field that stores types (including `Substitution` and the like), don't forget
/// `resolve_completely()`'ing them in `InferenceContext::resolve_all()`. Inference variables must
/// not appear in the final inference result.
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct InferenceResult {
/// For each method call expr, records the function it resolves to.
Expand Down Expand Up @@ -575,6 +579,8 @@ impl<'a> InferenceContext<'a> {
// used this function for another workaround, mention it here. If you really need this function and believe that
// there is no problem in it being `pub(crate)`, remove this comment.
pub(crate) fn resolve_all(self) -> InferenceResult {
// NOTE: `InferenceResult::closure_info` is `resolve_completely()`'d during
// `InferenceContext::infer_closures()` (in `HirPlace::ty()` specifically).
let InferenceContext { mut table, mut result, .. } = self;
Copy link
Member

@Veykril Veykril Jun 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given your comment, it might help to destructure result here so that when a new field is added it will error here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea, I'll do that!


table.fallback_if_possible();
Expand Down
62 changes: 26 additions & 36 deletions crates/hir-ty/src/infer/closure.rs
Expand Up @@ -5,7 +5,7 @@ use std::{cmp, collections::HashMap, convert::Infallible, mem};
use chalk_ir::{
cast::Cast,
fold::{FallibleTypeFolder, TypeFoldable},
AliasEq, AliasTy, BoundVar, ConstData, DebruijnIndex, FnSubst, Mutability, TyKind, WhereClause,
AliasEq, AliasTy, BoundVar, DebruijnIndex, FnSubst, Mutability, TyKind, WhereClause,
};
use hir_def::{
data::adt::VariantData,
Expand All @@ -26,8 +26,8 @@ use crate::{
static_lifetime, to_chalk_trait_id,
traits::FnTrait,
utils::{self, generics, Generics},
Adjust, Adjustment, Binders, BindingMode, ChalkTraitId, ClosureId, ConstValue, DynTy,
FnPointer, FnSig, Interner, Substitution, Ty, TyExt,
Adjust, Adjustment, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, FnPointer, FnSig,
Interner, Substitution, Ty, TyExt,
};

use super::{Expectation, InferenceContext};
Expand Down Expand Up @@ -236,6 +236,24 @@ pub(crate) struct CapturedItemWithoutTy {

impl CapturedItemWithoutTy {
fn with_ty(self, ctx: &mut InferenceContext<'_>) -> CapturedItem {
let ty = self.place.ty(ctx).clone();
let ty = match &self.kind {
CaptureKind::ByValue => ty,
CaptureKind::ByRef(bk) => {
let m = match bk {
BorrowKind::Mut { .. } => Mutability::Mut,
_ => Mutability::Not,
};
TyKind::Ref(m, static_lifetime(), ty).intern(Interner)
}
};
return CapturedItem {
place: self.place,
kind: self.kind,
span: self.span,
ty: replace_placeholder_with_binder(ctx.db, ctx.owner, ty),
};

fn replace_placeholder_with_binder(
db: &dyn HirDatabase,
owner: DefWithBodyId,
Expand Down Expand Up @@ -266,56 +284,28 @@ impl CapturedItemWithoutTy {
let Some(idx) = self.generics.param_idx(x) else {
return Err(());
};
Ok(ConstData {
ty,
value: ConstValue::BoundVar(BoundVar::new(outer_binder, idx)),
}
.intern(Interner))
Ok(BoundVar::new(outer_binder, idx).to_const(Interner, ty))
}

fn try_fold_free_placeholder_ty(
&mut self,
idx: chalk_ir::PlaceholderIndex,
_outer_binder: DebruijnIndex,
outer_binder: DebruijnIndex,
) -> std::result::Result<Ty, Self::Error> {
let x = from_placeholder_idx(self.db, idx);
let Some(idx) = self.generics.param_idx(x) else {
return Err(());
};
Ok(TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx))
.intern(Interner))
Ok(BoundVar::new(outer_binder, idx).to_ty(Interner))
}
}
let g_def = match owner {
DefWithBodyId::FunctionId(f) => Some(f.into()),
DefWithBodyId::StaticId(_) => None,
DefWithBodyId::ConstId(f) => Some(f.into()),
DefWithBodyId::VariantId(f) => Some(f.into()),
};
let Some(generics) = g_def.map(|g_def| generics(db.upcast(), g_def)) else {
let Some(generic_def) = owner.as_generic_def_id() else {
return Binders::empty(Interner, ty);
};
let filler = &mut Filler { db, generics };
let filler = &mut Filler { db, generics: generics(db.upcast(), generic_def) };
let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty);
make_binders(db, &filler.generics, result)
}
let ty = self.place.ty(ctx).clone();
let ty = match &self.kind {
CaptureKind::ByValue => ty,
CaptureKind::ByRef(bk) => {
let m = match bk {
BorrowKind::Mut { .. } => Mutability::Mut,
_ => Mutability::Not,
};
TyKind::Ref(m, static_lifetime(), ty).intern(Interner)
}
};
CapturedItem {
place: self.place,
kind: self.kind,
span: self.span,
ty: replace_placeholder_with_binder(ctx.db, ctx.owner, ty),
}
}
}

Expand Down
34 changes: 34 additions & 0 deletions crates/hir-ty/src/mir/eval/tests.rs
Expand Up @@ -640,3 +640,37 @@ fn main() {
"#,
);
}

#[test]
fn regression_14966() {
check_pass(
r#"
//- minicore: fn, copy, coerce_unsized
trait A<T> {
fn a(&self) {}
}
impl A<()> for () {}

struct B;
impl B {
pub fn b<T>(s: &dyn A<T>) -> Self {
B
}
}
struct C;
impl C {
fn c<T>(a: &dyn A<T>) -> Self {
let mut c = C;
let b = B::b(a);
c.d(|| a.a());
c
}
fn d(&mut self, f: impl FnOnce()) {}
}

fn main() {
C::c(&());
}
"#,
);
}
24 changes: 3 additions & 21 deletions crates/hir-ty/src/mir/monomorphization.rs
Expand Up @@ -303,13 +303,7 @@ pub fn monomorphized_mir_body_query(
subst: Substitution,
trait_env: Arc<crate::TraitEnvironment>,
) -> Result<Arc<MirBody>, MirLowerError> {
let g_def = match owner {
DefWithBodyId::FunctionId(f) => Some(f.into()),
DefWithBodyId::StaticId(_) => None,
DefWithBodyId::ConstId(f) => Some(f.into()),
DefWithBodyId::VariantId(f) => Some(f.into()),
};
let generics = g_def.map(|g_def| generics(db.upcast(), g_def));
let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
let body = db.mir_body(owner)?;
let mut body = (*body).clone();
Expand All @@ -334,13 +328,7 @@ pub fn monomorphized_mir_body_for_closure_query(
trait_env: Arc<crate::TraitEnvironment>,
) -> Result<Arc<MirBody>, MirLowerError> {
let (owner, _) = db.lookup_intern_closure(closure.into());
let g_def = match owner {
DefWithBodyId::FunctionId(f) => Some(f.into()),
DefWithBodyId::StaticId(_) => None,
DefWithBodyId::ConstId(f) => Some(f.into()),
DefWithBodyId::VariantId(f) => Some(f.into()),
};
let generics = g_def.map(|g_def| generics(db.upcast(), g_def));
let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
let body = db.mir_body_for_closure(closure)?;
let mut body = (*body).clone();
Expand All @@ -356,13 +344,7 @@ pub fn monomorphize_mir_body_bad(
trait_env: Arc<crate::TraitEnvironment>,
) -> Result<MirBody, MirLowerError> {
let owner = body.owner;
let g_def = match owner {
DefWithBodyId::FunctionId(f) => Some(f.into()),
DefWithBodyId::StaticId(_) => None,
DefWithBodyId::ConstId(f) => Some(f.into()),
DefWithBodyId::VariantId(f) => Some(f.into()),
};
let generics = g_def.map(|g_def| generics(db.upcast(), g_def));
let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
filler.fill_body(&mut body)?;
Ok(body)
Expand Down