Apply fallback to scalar type variables before final obligation resolution
This commit is contained in:
parent
b183612610
commit
d01630c8f3
@ -512,6 +512,8 @@ fn new(
|
|||||||
fn resolve_all(self) -> InferenceResult {
|
fn resolve_all(self) -> InferenceResult {
|
||||||
let InferenceContext { mut table, mut result, .. } = self;
|
let InferenceContext { mut table, mut result, .. } = self;
|
||||||
|
|
||||||
|
table.fallback_if_possible();
|
||||||
|
|
||||||
// FIXME resolve obligations as well (use Guidance if necessary)
|
// FIXME resolve obligations as well (use Guidance if necessary)
|
||||||
table.resolve_obligations_as_possible();
|
table.resolve_obligations_as_possible();
|
||||||
|
|
||||||
|
@ -350,6 +350,51 @@ pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
|
|||||||
self.resolve_with_fallback(t, &|_, _, d, _| d)
|
self.resolve_with_fallback(t, &|_, _, d, _| d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply a fallback to unresolved scalar types. Integer type variables and float type
|
||||||
|
/// variables are replaced with i32 and f64, respectively.
|
||||||
|
///
|
||||||
|
/// This method is only intended to be called just before returning inference results (i.e. in
|
||||||
|
/// `InferenceContext::resolve_all()`).
|
||||||
|
///
|
||||||
|
/// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
|
||||||
|
/// whereas rustc replaces them with `()` or `!`.
|
||||||
|
pub(super) fn fallback_if_possible(&mut self) {
|
||||||
|
let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
|
||||||
|
let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
|
||||||
|
|
||||||
|
let scalar_vars: Vec<_> = self
|
||||||
|
.type_variable_table
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(index, flags)| {
|
||||||
|
let kind = if flags.contains(TypeVariableFlags::INTEGER) {
|
||||||
|
TyVariableKind::Integer
|
||||||
|
} else if flags.contains(TypeVariableFlags::FLOAT) {
|
||||||
|
TyVariableKind::Float
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
|
||||||
|
// without directly constructing them from `index`?
|
||||||
|
let var = InferenceVar::from(index as u32).to_ty(Interner, kind);
|
||||||
|
Some(var)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for var in scalar_vars {
|
||||||
|
let maybe_resolved = self.resolve_ty_shallow(&var);
|
||||||
|
if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
|
||||||
|
let fallback = match kind {
|
||||||
|
TyVariableKind::Integer => &int_fallback,
|
||||||
|
TyVariableKind::Float => &float_fallback,
|
||||||
|
TyVariableKind::General => unreachable!(),
|
||||||
|
};
|
||||||
|
self.unify(&var, fallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
|
/// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
|
||||||
pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
|
pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
|
||||||
let result = match self.try_unify(ty1, ty2) {
|
let result = match self.try_unify(ty1, ty2) {
|
||||||
|
@ -4100,3 +4100,68 @@ fn f<T>(t: T)
|
|||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bin_op_with_scalar_fallback() {
|
||||||
|
// Extra impls are significant so that chalk doesn't give us definite guidances.
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
//- minicore: add
|
||||||
|
use core::ops::Add;
|
||||||
|
|
||||||
|
struct Vec2<T>(T, T);
|
||||||
|
|
||||||
|
impl Add for Vec2<i32> {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||||
|
}
|
||||||
|
impl Add for Vec2<u32> {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||||
|
}
|
||||||
|
impl Add for Vec2<f32> {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||||
|
}
|
||||||
|
impl Add for Vec2<f64> {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Self) -> Self::Output { loop {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let a = Vec2(1, 2);
|
||||||
|
let b = Vec2(3, 4);
|
||||||
|
let c = a + b;
|
||||||
|
//^ Vec2<i32>
|
||||||
|
let a = Vec2(1., 2.);
|
||||||
|
let b = Vec2(3., 4.);
|
||||||
|
let c = a + b;
|
||||||
|
//^ Vec2<f64>
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trait_method_with_scalar_fallback() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
trait Trait {
|
||||||
|
type Output;
|
||||||
|
fn foo(&self) -> Self::Output;
|
||||||
|
}
|
||||||
|
impl<T> Trait for T {
|
||||||
|
type Output = T;
|
||||||
|
fn foo(&self) -> Self::Output { loop {} }
|
||||||
|
}
|
||||||
|
fn test() {
|
||||||
|
let a = 42;
|
||||||
|
let b = a.foo();
|
||||||
|
//^ i32
|
||||||
|
let a = 3.14;
|
||||||
|
let b = a.foo();
|
||||||
|
//^ f64
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user