Skip to content

Commit 1f6ea3a

Browse files
committed
Flounder in function trait when inference var or type alias is encountered
1 parent f3763f3 commit 1f6ea3a

File tree

5 files changed

+47
-15
lines changed

5 files changed

+47
-15
lines changed

chalk-solve/src/clauses.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ fn program_clauses_that_could_match<I: Interner>(
295295
}
296296

297297
if let Some(well_known) = trait_datum.well_known {
298-
builtin_traits::add_builtin_program_clauses(db, builder, well_known, trait_ref);
298+
builtin_traits::add_builtin_program_clauses(db, builder, well_known, trait_ref)?;
299299
}
300300
}
301301
DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => match &alias_eq.alias {
@@ -370,7 +370,7 @@ fn program_clauses_that_could_match<I: Interner>(
370370
if let Some(well_known) = trait_datum.well_known {
371371
builtin_traits::add_builtin_assoc_program_clauses(
372372
db, builder, well_known, self_ty,
373-
);
373+
)?;
374374
}
375375

376376
push_program_clauses_for_associated_type_values_in_impls_of(

chalk-solve/src/clauses/builder.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> {
114114
/// The new binders are always pushed onto the end of the internal
115115
/// list of binders; this means that any extant values where were
116116
/// created referencing the *old* list of binders are still valid.
117-
pub fn push_binders<V>(&mut self, binders: &Binders<V>, op: impl FnOnce(&mut Self, V::Result))
117+
pub fn push_binders<R, V>(
118+
&mut self,
119+
binders: &Binders<V>,
120+
op: impl FnOnce(&mut Self, V::Result) -> R,
121+
) -> R
118122
where
119123
V: Fold<I> + HasInterner<Interner = I>,
120124
V::Result: std::fmt::Debug,
@@ -134,10 +138,11 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> {
134138

135139
let value = binders.substitute(self.interner(), &self.parameters[old_len..]);
136140
debug!("push_binders: value={:?}", value);
137-
op(self, value);
141+
let res = op(self, value);
138142

139143
self.binders.truncate(old_len);
140144
self.parameters.truncate(old_len);
145+
res
141146
}
142147

143148
/// Push a single binder, for a type, at the end of the binder

chalk-solve/src/clauses/builtin_traits.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{builder::ClauseBuilder, generalize};
22
use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait};
3-
use chalk_ir::{Substitution, Ty};
3+
use chalk_ir::{Floundered, Substitution, Ty};
44

55
mod clone;
66
mod copy;
@@ -14,7 +14,7 @@ pub fn add_builtin_program_clauses<I: Interner>(
1414
builder: &mut ClauseBuilder<'_, I>,
1515
well_known: WellKnownTrait,
1616
trait_ref: &TraitRef<I>,
17-
) {
17+
) -> Result<(), Floundered> {
1818
// If `trait_ref` contains bound vars, we want to universally quantify them.
1919
// `Generalize` collects them for us.
2020
let generalized = generalize::Generalize::apply(db.interner(), trait_ref);
@@ -26,20 +26,21 @@ pub fn add_builtin_program_clauses<I: Interner>(
2626
if force_impl {
2727
builder.push_fact(trait_ref.clone());
2828
}
29-
return;
29+
return Ok(());
3030
}
3131

3232
match well_known {
3333
WellKnownTrait::Sized => sized::add_sized_program_clauses(db, builder, &trait_ref, ty),
3434
WellKnownTrait::Copy => copy::add_copy_program_clauses(db, builder, &trait_ref, ty),
3535
WellKnownTrait::Clone => clone::add_clone_program_clauses(db, builder, &trait_ref, ty),
3636
WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn => {
37-
fn_family::add_fn_trait_program_clauses(db, builder, trait_ref.trait_id, self_ty)
37+
fn_family::add_fn_trait_program_clauses(db, builder, trait_ref.trait_id, self_ty)?
3838
}
3939
// Drop impls are provided explicitly
4040
WellKnownTrait::Drop => (),
4141
}
42-
});
42+
Ok(())
43+
})
4344
}
4445

4546
/// Like `add_builtin_program_clauses`, but for `DomainGoal::Normalize` involving
@@ -49,14 +50,15 @@ pub fn add_builtin_assoc_program_clauses<I: Interner>(
4950
builder: &mut ClauseBuilder<'_, I>,
5051
well_known: WellKnownTrait,
5152
self_ty: Ty<I>,
52-
) {
53+
) -> Result<(), Floundered> {
5354
match well_known {
5455
WellKnownTrait::FnOnce => {
5556
let trait_id = db.well_known_trait_id(well_known).unwrap();
56-
fn_family::add_fn_trait_program_clauses(db, builder, trait_id, self_ty);
57+
fn_family::add_fn_trait_program_clauses(db, builder, trait_id, self_ty)?;
5758
}
5859
_ => {}
5960
}
61+
Ok(())
6062
}
6163

6264
/// Given a trait ref `T0: Trait` and a list of types `U0..Un`, pushes a clause of the form

chalk-solve/src/clauses/builtin_traits/fn_family.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use crate::infer::instantiate::IntoBindersAndValue;
33
use crate::rust_ir::WellKnownTrait;
44
use crate::{Interner, RustIrDatabase, TraitRef};
55
use chalk_ir::{
6-
AliasTy, ApplicationTy, Binders, Normalize, ProjectionTy, Substitution, TraitId, Ty, TyData,
7-
TypeName, VariableKinds,
6+
AliasTy, ApplicationTy, Binders, Floundered, Normalize, ProjectionTy, Substitution, TraitId,
7+
Ty, TyData, TypeName, VariableKinds,
88
};
99

1010
/// Handles clauses for FnOnce/FnMut/Fn.
@@ -21,7 +21,7 @@ pub fn add_fn_trait_program_clauses<I: Interner>(
2121
builder: &mut ClauseBuilder<'_, I>,
2222
trait_id: TraitId<I>,
2323
self_ty: Ty<I>,
24-
) {
24+
) -> Result<(), Floundered> {
2525
let interner = db.interner();
2626
match self_ty.data(interner) {
2727
TyData::Function(fn_val) => {
@@ -81,7 +81,10 @@ pub fn add_fn_trait_program_clauses<I: Interner>(
8181
builder.push_fact(normalize);
8282
}
8383
});
84+
Ok(())
8485
}
85-
_ => {}
86+
// Function traits are non-enumerable
87+
TyData::InferenceVar(..) | TyData::Alias(..) => Err(Floundered),
88+
_ => Ok(()),
8689
}
8790
}

tests/test/functions.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ fn function_implement_fn_traits() {
1414

1515
#[lang(fn)]
1616
trait Fn<Args> where Self: FnMut<Args> { }
17+
18+
struct Ty { }
19+
20+
trait Clone { }
21+
opaque type MyOpaque: Clone = Ty;
22+
1723
}
1824

1925
// Simple test: make sure a fully monomorphic type implements FnOnce
@@ -156,6 +162,22 @@ fn function_implement_fn_traits() {
156162
} yields {
157163
"No possible solution"
158164
}
165+
166+
// Tests that we flounder for inference variables
167+
goal {
168+
exists<T> {
169+
T: FnOnce<()>
170+
}
171+
} yields_first[SolverChoice::slg(3, None)] {
172+
"Floundered"
173+
}
174+
175+
// Tests that we flounder for alias type (opaque)
176+
goal {
177+
MyOpaque: FnOnce<()>
178+
} yields_first[SolverChoice::slg(3, None)] {
179+
"Floundered"
180+
}
159181
}
160182
}
161183

0 commit comments

Comments
 (0)