Skip to content

Commit 9034552

Browse files
committed
Handle ambiguous projections
1 parent b528cc9 commit 9034552

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

clippy_lints/src/dereference.rs

+27-9
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_hir::{
2121
TraitItemKind, TyKind, UnOp,
2222
};
2323
use rustc_index::bit_set::BitSet;
24-
use rustc_infer::infer::TyCtxtInferExt;
24+
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
2525
use rustc_lint::{LateContext, LateLintPass};
2626
use rustc_middle::mir::{Rvalue, StatementKind};
2727
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@@ -31,8 +31,9 @@ use rustc_middle::ty::{
3131
};
3232
use rustc_session::{declare_tool_lint, impl_lint_pass};
3333
use rustc_span::{symbol::sym, Span, Symbol};
34-
use rustc_trait_selection::infer::InferCtxtExt as _;
35-
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
34+
use rustc_trait_selection::infer::{canonical::OriginalQueryValues, InferCtxtExt as _};
35+
use rustc_trait_selection::traits::query::{evaluate_obligation::InferCtxtExt as _, NormalizationResult};
36+
use rustc_trait_selection::traits::{Obligation, ObligationCause};
3637
use std::collections::VecDeque;
3738

3839
declare_clippy_lint! {
@@ -1359,13 +1360,30 @@ fn replace_types<'tcx>(
13591360
{
13601361
let item_def_id = projection_predicate.projection_ty.def_id;
13611362
let assoc_item = cx.tcx.associated_item(item_def_id);
1362-
let projection = cx.tcx
1363-
.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, []));
1364-
1365-
if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
1366-
&& substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
1363+
let alias_ty = cx
1364+
.tcx
1365+
.mk_alias_ty(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, []));
1366+
1367+
// The following normalization method is based on:
1368+
// https://github.com/rust-lang/rust/blob/695072daa6cc04045f2aa79d751d884ad5263080/compiler/rustc_trait_selection/src/traits/query/normalize.rs#L258-L285
1369+
// It is meant to address: https://github.com/rust-lang/rust/issues/107877
1370+
let infcx = cx.tcx.infer_ctxt().build();
1371+
let mut orig_values = OriginalQueryValues::default();
1372+
let canonical_ty =
1373+
infcx.canonicalize_query_keep_static(cx.param_env.and(alias_ty), &mut orig_values);
1374+
1375+
if let Ok(result) = cx.tcx.normalize_projection_ty(canonical_ty)
1376+
&& !result.is_ambiguous()
1377+
&& let Ok(InferOk { value: NormalizationResult { normalized_ty, .. }, .. }) =
1378+
infcx.instantiate_query_response_and_region_obligations(
1379+
&ObligationCause::dummy(),
1380+
cx.param_env,
1381+
&orig_values,
1382+
result,
1383+
)
1384+
&& substs[term_param_ty.index as usize] != ty::GenericArg::from(normalized_ty)
13671385
{
1368-
deque.push_back((*term_param_ty, projected_ty));
1386+
deque.push_back((*term_param_ty, normalized_ty));
13691387
}
13701388
}
13711389
}

tests/ui/crashes/ice-rust-107877.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![allow(dead_code)]
2+
3+
struct Foo;
4+
5+
impl<'a> std::convert::TryFrom<&'a String> for &'a Foo {
6+
type Error = ();
7+
8+
fn try_from(_: &'a String) -> Result<Self, Self::Error> {
9+
Ok(&Foo)
10+
}
11+
}
12+
13+
fn find<'a, E>(_: impl TryInto<&'a Foo, Error = E>) {}
14+
15+
fn main() {
16+
find(&String::new());
17+
}

0 commit comments

Comments
 (0)