Skip to content

Commit 784c7a6

Browse files
only mark projection as ambiguous if GAT substs are constrained
1 parent e646f3d commit 784c7a6

File tree

6 files changed

+89
-44
lines changed

6 files changed

+89
-44
lines changed

compiler/rustc_infer/src/infer/type_variable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
259259
let index = self.values().push(TypeVariableData { origin });
260260
assert_eq!(eq_key.vid.as_u32(), index as u32);
261261

262-
debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,);
262+
debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin);
263263

264264
eq_key.vid
265265
}

compiler/rustc_trait_selection/src/traits/project.rs

+27-30
Original file line numberDiff line numberDiff line change
@@ -1073,16 +1073,6 @@ fn project<'cx, 'tcx>(
10731073
return Ok(Projected::Progress(Progress::error(selcx.tcx())));
10741074
}
10751075

1076-
// If the obligation contains any inference types or consts in associated
1077-
// type substs, then we don't assemble any candidates.
1078-
// This isn't really correct, but otherwise we can end up in a case where
1079-
// we constrain inference variables by selecting a single predicate, when
1080-
// we need to stay general. See issue #91762.
1081-
let (_, predicate_own_substs) = obligation.predicate.trait_ref_and_own_substs(selcx.tcx());
1082-
if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) {
1083-
return Err(ProjectionError::TooManyCandidates);
1084-
}
1085-
10861076
let mut candidates = ProjectionCandidateSet::None;
10871077

10881078
// Make sure that the following procedures are kept in order. ParamEnv
@@ -1180,7 +1170,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
11801170
ProjectionCandidate::TraitDef,
11811171
bounds.iter(),
11821172
true,
1183-
)
1173+
);
11841174
}
11851175

11861176
/// In the case of a trait object like
@@ -1245,27 +1235,34 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
12451235
let bound_predicate = predicate.kind();
12461236
if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
12471237
let data = bound_predicate.rebind(data);
1248-
let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
1249-
1250-
let is_match = same_def_id
1251-
&& infcx.probe(|_| {
1252-
selcx.match_projection_projections(
1253-
obligation,
1254-
data,
1255-
potentially_unnormalized_candidates,
1256-
)
1257-
});
1238+
if data.projection_def_id() != obligation.predicate.item_def_id {
1239+
continue;
1240+
}
12581241

1259-
if is_match {
1260-
candidate_set.push_candidate(ctor(data));
1242+
let is_match = infcx.probe(|_| {
1243+
selcx.match_projection_projections(
1244+
obligation,
1245+
data,
1246+
potentially_unnormalized_candidates,
1247+
)
1248+
});
12611249

1262-
if potentially_unnormalized_candidates
1263-
&& !obligation.predicate.has_infer_types_or_consts()
1264-
{
1265-
// HACK: Pick the first trait def candidate for a fully
1266-
// inferred predicate. This is to allow duplicates that
1267-
// differ only in normalization.
1268-
return;
1250+
match is_match {
1251+
Some(true) => {
1252+
candidate_set.push_candidate(ctor(data));
1253+
1254+
if potentially_unnormalized_candidates
1255+
&& !obligation.predicate.has_infer_types_or_consts()
1256+
{
1257+
// HACK: Pick the first trait def candidate for a fully
1258+
// inferred predicate. This is to allow duplicates that
1259+
// differ only in normalization.
1260+
return;
1261+
}
1262+
}
1263+
Some(false) => {}
1264+
None => {
1265+
candidate_set.mark_ambiguous();
12691266
}
12701267
}
12711268
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -1508,12 +1508,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15081508
})
15091509
}
15101510

1511+
/// Return Some(true) if the obligation's predicate type applies to the env_predicate, and
1512+
/// Some(false) if it does not. Returns None in the case that the projection type is a GAT,
1513+
/// and applying this env_predicate constrains any of the obligation's GAT substitutions.
15111514
pub(super) fn match_projection_projections(
15121515
&mut self,
15131516
obligation: &ProjectionTyObligation<'tcx>,
15141517
env_predicate: PolyProjectionPredicate<'tcx>,
15151518
potentially_unnormalized_candidates: bool,
1516-
) -> bool {
1519+
) -> Option<bool> {
15171520
let mut nested_obligations = Vec::new();
15181521
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
15191522
obligation.cause.span,
@@ -1535,7 +1538,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15351538
infer_predicate.projection_ty
15361539
};
15371540

1538-
self.infcx
1541+
let is_match = self
1542+
.infcx
15391543
.at(&obligation.cause, obligation.param_env)
15401544
.define_opaque_types(false)
15411545
.sup(obligation.predicate, infer_projection)
@@ -1545,7 +1549,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15451549
nested_obligations.into_iter().chain(obligations),
15461550
)
15471551
.map_or(false, |res| res.may_apply())
1548-
})
1552+
});
1553+
1554+
if is_match {
1555+
let generics = self.tcx().generics_of(obligation.predicate.item_def_id);
1556+
if !generics.params.is_empty() {
1557+
// If any of the obligation's predicate substs shallow-resolve to
1558+
// something new, that means that we must have newly inferred something
1559+
// about the GAT. We should give up with ambiguity in that case.
1560+
if obligation.predicate.substs[generics.parent_count..]
1561+
.iter()
1562+
.any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p)
1563+
{
1564+
return None;
1565+
}
1566+
}
1567+
}
1568+
1569+
Some(is_match)
15491570
}
15501571

15511572
///////////////////////////////////////////////////////////////////////////

src/test/ui/generic-associated-types/issue-74824.rs

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ impl<T> UnsafeCopy for T {}
1717
fn main() {
1818
let b = Box::new(42usize);
1919
let copy = <()>::copy(&b);
20-
//~^ type annotations needed
2120

2221
let raw_b = Box::deref(&b) as *const _;
2322
let raw_copy = Box::deref(&copy) as *const _;

src/test/ui/generic-associated-types/issue-74824.stderr

+2-9
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@ help: consider restricting type parameter `T`
2727
LL | type Copy<T: std::clone::Clone>: Copy = Box<T>;
2828
| +++++++++++++++++++
2929

30-
error[E0282]: type annotations needed
31-
--> $DIR/issue-74824.rs:19:16
32-
|
33-
LL | let copy = <()>::copy(&b);
34-
| ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `copy`
35-
36-
error: aborting due to 3 previous errors
30+
error: aborting due to 2 previous errors
3731

38-
Some errors have detailed explanations: E0277, E0282.
39-
For more information about an error, try `rustc --explain E0277`.
32+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// check-pass
2+
3+
#![feature(generic_associated_types)]
4+
5+
pub trait Build {
6+
type Output<O>;
7+
fn build<O>(self, input: O) -> Self::Output<O>;
8+
}
9+
10+
pub struct IdentityBuild;
11+
impl Build for IdentityBuild {
12+
type Output<O> = O;
13+
fn build<O>(self, input: O) -> Self::Output<O> {
14+
input
15+
}
16+
}
17+
18+
fn a() {
19+
let _x: u8 = IdentityBuild.build(10);
20+
}
21+
22+
fn b() {
23+
let _x: Vec<u8> = IdentityBuild.build(Vec::new());
24+
}
25+
26+
fn c() {
27+
let mut f = IdentityBuild.build(|| ());
28+
(f)();
29+
}
30+
31+
pub fn main() {
32+
a();
33+
b();
34+
c();
35+
}

0 commit comments

Comments
 (0)