Skip to content

Commit d01630c

Browse files
committed
Apply fallback to scalar type variables before final obligation resolution
1 parent b183612 commit d01630c

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

crates/hir-ty/src/infer.rs

+2
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,8 @@ impl<'a> InferenceContext<'a> {
512512
fn resolve_all(self) -> InferenceResult {
513513
let InferenceContext { mut table, mut result, .. } = self;
514514

515+
table.fallback_if_possible();
516+
515517
// FIXME resolve obligations as well (use Guidance if necessary)
516518
table.resolve_obligations_as_possible();
517519

crates/hir-ty/src/infer/unify.rs

+45
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,51 @@ impl<'a> InferenceTable<'a> {
350350
self.resolve_with_fallback(t, &|_, _, d, _| d)
351351
}
352352

353+
/// Apply a fallback to unresolved scalar types. Integer type variables and float type
354+
/// variables are replaced with i32 and f64, respectively.
355+
///
356+
/// This method is only intended to be called just before returning inference results (i.e. in
357+
/// `InferenceContext::resolve_all()`).
358+
///
359+
/// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
360+
/// whereas rustc replaces them with `()` or `!`.
361+
pub(super) fn fallback_if_possible(&mut self) {
362+
let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
363+
let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
364+
365+
let scalar_vars: Vec<_> = self
366+
.type_variable_table
367+
.iter()
368+
.enumerate()
369+
.filter_map(|(index, flags)| {
370+
let kind = if flags.contains(TypeVariableFlags::INTEGER) {
371+
TyVariableKind::Integer
372+
} else if flags.contains(TypeVariableFlags::FLOAT) {
373+
TyVariableKind::Float
374+
} else {
375+
return None;
376+
};
377+
378+
// FIXME: This is not really the nicest way to get `InferenceVar`s. Can we get them
379+
// without directly constructing them from `index`?
380+
let var = InferenceVar::from(index as u32).to_ty(Interner, kind);
381+
Some(var)
382+
})
383+
.collect();
384+
385+
for var in scalar_vars {
386+
let maybe_resolved = self.resolve_ty_shallow(&var);
387+
if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
388+
let fallback = match kind {
389+
TyVariableKind::Integer => &int_fallback,
390+
TyVariableKind::Float => &float_fallback,
391+
TyVariableKind::General => unreachable!(),
392+
};
393+
self.unify(&var, fallback);
394+
}
395+
}
396+
}
397+
353398
/// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
354399
pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
355400
let result = match self.try_unify(ty1, ty2) {

crates/hir-ty/src/tests/traits.rs

+65
Original file line numberDiff line numberDiff line change
@@ -4100,3 +4100,68 @@ where
41004100
"#,
41014101
);
41024102
}
4103+
4104+
#[test]
4105+
fn bin_op_with_scalar_fallback() {
4106+
// Extra impls are significant so that chalk doesn't give us definite guidances.
4107+
check_types(
4108+
r#"
4109+
//- minicore: add
4110+
use core::ops::Add;
4111+
4112+
struct Vec2<T>(T, T);
4113+
4114+
impl Add for Vec2<i32> {
4115+
type Output = Self;
4116+
fn add(self, rhs: Self) -> Self::Output { loop {} }
4117+
}
4118+
impl Add for Vec2<u32> {
4119+
type Output = Self;
4120+
fn add(self, rhs: Self) -> Self::Output { loop {} }
4121+
}
4122+
impl Add for Vec2<f32> {
4123+
type Output = Self;
4124+
fn add(self, rhs: Self) -> Self::Output { loop {} }
4125+
}
4126+
impl Add for Vec2<f64> {
4127+
type Output = Self;
4128+
fn add(self, rhs: Self) -> Self::Output { loop {} }
4129+
}
4130+
4131+
fn test() {
4132+
let a = Vec2(1, 2);
4133+
let b = Vec2(3, 4);
4134+
let c = a + b;
4135+
//^ Vec2<i32>
4136+
let a = Vec2(1., 2.);
4137+
let b = Vec2(3., 4.);
4138+
let c = a + b;
4139+
//^ Vec2<f64>
4140+
}
4141+
"#,
4142+
);
4143+
}
4144+
4145+
#[test]
4146+
fn trait_method_with_scalar_fallback() {
4147+
check_types(
4148+
r#"
4149+
trait Trait {
4150+
type Output;
4151+
fn foo(&self) -> Self::Output;
4152+
}
4153+
impl<T> Trait for T {
4154+
type Output = T;
4155+
fn foo(&self) -> Self::Output { loop {} }
4156+
}
4157+
fn test() {
4158+
let a = 42;
4159+
let b = a.foo();
4160+
//^ i32
4161+
let a = 3.14;
4162+
let b = a.foo();
4163+
//^ f64
4164+
}
4165+
"#,
4166+
);
4167+
}

0 commit comments

Comments
 (0)