Skip to content

Commit

Permalink
fix: Allow unknown guidance when try to coerce unsized
Browse files Browse the repository at this point in the history
  • Loading branch information
Austaras committed Jan 4, 2024
1 parent c3a00b5 commit d9fb761
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 15 deletions.
41 changes: 26 additions & 15 deletions crates/hir-ty/src/infer/coerce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use std::iter;

use chalk_ir::{cast::Cast, BoundVar, Goal, Mutability, TyKind, TyVariableKind};
use chalk_ir::{cast::Cast, BoundVar, Mutability, TyKind, TyVariableKind};
use hir_def::{
hir::ExprId,
lang_item::{LangItem, LangItemTarget},
Expand All @@ -24,8 +24,8 @@ use crate::{
},
static_lifetime,
utils::ClosureSubst,
Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner, Solution,
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
Canonical, FnPointer, FnSig, Goal, Guidance, InEnvironment, Interner, Solution, Substitution,
TraitEnvironment, Ty, TyBuilder, TyExt,
};

use super::unify::InferenceTable;
Expand All @@ -42,11 +42,7 @@ fn simple(kind: Adjust) -> impl FnOnce(Ty) -> Vec<Adjustment> {
}

/// This always returns `Ok(...)`.
fn success(
adj: Vec<Adjustment>,
target: Ty,
goals: Vec<InEnvironment<Goal<Interner>>>,
) -> CoerceResult {
fn success(adj: Vec<Adjustment>, target: Ty, goals: Vec<InEnvironment<Goal>>) -> CoerceResult {
Ok(InferOk { goals, value: (adj, target) })
}

Expand Down Expand Up @@ -229,8 +225,6 @@ impl InferenceContext<'_> {
from_ty: &Ty,
to_ty: &Ty,
) -> Result<Ty, TypeError> {
let from_ty = self.resolve_ty_shallow(from_ty);
let to_ty = self.resolve_ty_shallow(to_ty);
let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty)?;
if let Some(expr) = expr {
self.write_expr_adj(expr, adjustments);
Expand Down Expand Up @@ -411,10 +405,10 @@ impl InferenceTable<'_> {
// mutability [1], since it may be that we are coercing
// from `&mut T` to `&U`.
let lt = static_lifetime(); // FIXME: handle lifetimes correctly, see rustc
let derefd_from_ty = TyKind::Ref(to_mt, lt, referent_ty).intern(Interner);
match autoderef.table.try_unify(&derefd_from_ty, to_ty) {
let derefed_from_ty = TyKind::Ref(to_mt, lt, referent_ty).intern(Interner);
match autoderef.table.try_unify(&derefed_from_ty, to_ty) {
Ok(result) => {
found = Some(result.map(|()| derefd_from_ty));
found = Some(result.map(|()| derefed_from_ty));
break;
}
Err(err) => {
Expand Down Expand Up @@ -626,6 +620,7 @@ impl InferenceTable<'_> {
}
_ => None,
};
let must_be_unsized = must_be_coerce_unsized(from_ty, to_ty);
let coerce_from =
reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());

Expand All @@ -644,7 +639,7 @@ impl InferenceTable<'_> {
b.push(coerce_from).push(to_ty.clone()).build()
};

let goal: InEnvironment<DomainGoal> =
let goal: InEnvironment<Goal> =
InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner));

let canonicalized = self.canonicalize(goal);
Expand Down Expand Up @@ -673,7 +668,10 @@ impl InferenceTable<'_> {
// FIXME need to record an obligation here
canonicalized.apply_solution(self, subst)
}
// FIXME actually we maybe should also accept unknown guidance here
// FIXME workaround for #11847 and #15984, maybe removed after new trait solver
Solution::Ambig(Guidance::Unknown) if must_be_unsized => {
// FIXME need to record an obligation here too
}
_ => return Err(TypeError),
};
let unsize =
Expand Down Expand Up @@ -715,6 +713,19 @@ fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError
}
}

// a temporary workaroud for coerce_unsized
fn must_be_coerce_unsized(from_ty: &Ty, to_ty: &Ty) -> bool {
// FIXME: many other cases
match (from_ty.kind(Interner), to_ty.kind(Interner)) {
(TyKind::Ref(_, _, from_ty), TyKind::Ref(_, _, to_ty)) => {
must_be_coerce_unsized(from_ty, to_ty)
}
(_, TyKind::Dyn(_)) => true,
(TyKind::Array(_, _), TyKind::Slice(_)) => true,
(_, _) => false,
}
}

pub(super) fn auto_deref_adjust_steps(autoderef: &Autoderef<'_, '_>) -> Vec<Adjustment> {
let steps = autoderef.steps();
let targets =
Expand Down
45 changes: 45 additions & 0 deletions crates/hir-ty/src/tests/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -941,3 +941,48 @@ fn main() {
"#,
)
}

#[test]
fn coerce_unsized_impl_trait() {
check_no_mismatches(
r#"
//- minicore: coerce_unsized
struct Sender<T>;
impl<T> Sender<T> {
fn send(&self, msg: T) {}
}
trait SelectHandle {}
impl<T> SelectHandle for Sender<T> {}
impl<T: SelectHandle> SelectHandle for &T {}
fn foo() {
let sender = Sender;
let _handle: &dyn SelectHandle = &sender;
sender.send(0_usize);
}
"#,
);
}

#[test]
fn coerce_unsized_impl_trait2() {
check_no_mismatches(
r#"
//- minicore: fmt, coerce_unsized
fn print_me_later(x: &dyn Debug) -> impl FnOnce() + '_ {
move || println!("{x:?}")
}
fn main() {
let f = print_me_later(&22);
f()
}
"#,
);
}

0 comments on commit d9fb761

Please sign in to comment.