Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f705de5

Browse files
committedApr 30, 2024
Auto merge of #117164 - fmease:orphan-norm, r=lcnr
Lazily normalize inside trait ref during orphan check & consider ty params in rigid alias types to be uncovered Fixes #99554, fixes rust-lang/types-team#104. Fixes #114061. Supersedes #100555. Tracking issue for the future compatibility lint: #124559. r? lcnr
2 parents 4f81879 + 951e902 commit f705de5

File tree

33 files changed

+1054
-144
lines changed

33 files changed

+1054
-144
lines changed
 

‎compiler/rustc_hir_analysis/messages.ftl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -486,13 +486,13 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de
486486
487487
hir_analysis_ty_of_assoc_const_binding_note = `{$assoc_const}` has type `{$ty}`
488488
489-
hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
490-
.label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
489+
hir_analysis_ty_param_first_local = type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)
490+
.label = type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)
491491
.note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
492492
.case_note = in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
493493
494-
hir_analysis_ty_param_some = type parameter `{$param_ty}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param_ty}>`)
495-
.label = type parameter `{$param_ty}` must be used as the type parameter for some local type
494+
hir_analysis_ty_param_some = type parameter `{$param}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param}>`)
495+
.label = type parameter `{$param}` must be used as the type parameter for some local type
496496
.note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
497497
.only_note = only traits defined in the current crate can be implemented for a type parameter
498498

‎compiler/rustc_hir_analysis/src/coherence/orphan.rs

Lines changed: 245 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,44 @@
22
//! crate or pertains to a type defined in this crate.
33
44
use crate::errors;
5+
6+
use rustc_data_structures::fx::FxIndexSet;
57
use rustc_errors::ErrorGuaranteed;
6-
use rustc_hir as hir;
7-
use rustc_middle::ty::{self, AliasKind, TyCtxt, TypeVisitableExt};
8-
use rustc_span::def_id::LocalDefId;
9-
use rustc_span::Span;
10-
use rustc_trait_selection::traits::{self, IsFirstInputType};
8+
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
9+
use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
10+
use rustc_middle::ty::{self, Ty, TyCtxt};
11+
use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
12+
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
13+
use rustc_span::def_id::{DefId, LocalDefId};
14+
use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams};
15+
use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode};
16+
use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt};
1117

12-
#[instrument(skip(tcx), level = "debug")]
18+
#[instrument(level = "debug", skip(tcx))]
1319
pub(crate) fn orphan_check_impl(
1420
tcx: TyCtxt<'_>,
1521
impl_def_id: LocalDefId,
1622
) -> Result<(), ErrorGuaranteed> {
1723
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
1824
trait_ref.error_reported()?;
1925

20-
let trait_def_id = trait_ref.def_id;
21-
22-
match traits::orphan_check(tcx, impl_def_id.to_def_id()) {
26+
match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) {
2327
Ok(()) => {}
24-
Err(err) => {
25-
let item = tcx.hir().expect_item(impl_def_id);
26-
let hir::ItemKind::Impl(impl_) = item.kind else {
27-
bug!("{:?} is not an impl: {:?}", impl_def_id, item);
28-
};
29-
let tr = impl_.of_trait.as_ref().unwrap();
30-
let sp = tcx.def_span(impl_def_id);
31-
32-
emit_orphan_check_error(
33-
tcx,
34-
sp,
35-
item.span,
36-
tr.path.span,
37-
trait_ref,
38-
impl_.self_ty.span,
39-
impl_.generics,
40-
err,
41-
)?
42-
}
28+
Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) {
29+
Ok(()) => match err {
30+
OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => {
31+
lint_uncovered_ty_params(tcx, uncovered_ty_params, impl_def_id)
32+
}
33+
OrphanCheckErr::NonLocalInputType(_) => {
34+
bug!("orphanck: shouldn't've gotten non-local input tys in compat mode")
35+
}
36+
},
37+
Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)),
38+
},
4339
}
4440

41+
let trait_def_id = trait_ref.def_id;
42+
4543
// In addition to the above rules, we restrict impls of auto traits
4644
// so that they can only be implemented on nominal types, such as structs,
4745
// enums or foreign types. To see why this restriction exists, consider the
@@ -186,13 +184,13 @@ pub(crate) fn orphan_check_impl(
186184
// type This = T;
187185
// }
188186
// impl<T: ?Sized> AutoTrait for <T as Id>::This {}
189-
AliasKind::Projection => "associated type",
187+
ty::Projection => "associated type",
190188
// type Foo = (impl Sized, bool)
191189
// impl AutoTrait for Foo {}
192-
AliasKind::Weak => "type alias",
190+
ty::Weak => "type alias",
193191
// type Opaque = impl Trait;
194192
// impl AutoTrait for Opaque {}
195-
AliasKind::Opaque => "opaque type",
193+
ty::Opaque => "opaque type",
196194
// ```
197195
// struct S<T>(T);
198196
// impl<T: ?Sized> S<T> {
@@ -201,7 +199,7 @@ pub(crate) fn orphan_check_impl(
201199
// impl<T: ?Sized> AutoTrait for S<T>::This {}
202200
// ```
203201
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
204-
AliasKind::Inherent => "associated type",
202+
ty::Inherent => "associated type",
205203
};
206204
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
207205
}
@@ -275,34 +273,125 @@ pub(crate) fn orphan_check_impl(
275273
Ok(())
276274
}
277275

276+
/// Checks the coherence orphan rules.
277+
///
278+
/// `impl_def_id` should be the `DefId` of a trait impl.
279+
///
280+
/// To pass, either the trait must be local, or else two conditions must be satisfied:
281+
///
282+
/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
283+
/// 2. Some local type must appear in `Self`.
284+
#[instrument(level = "debug", skip(tcx), ret)]
285+
fn orphan_check<'tcx>(
286+
tcx: TyCtxt<'tcx>,
287+
impl_def_id: LocalDefId,
288+
mode: OrphanCheckMode,
289+
) -> Result<(), OrphanCheckErr<'tcx, FxIndexSet<DefId>>> {
290+
// We only accept this routine to be invoked on implementations
291+
// of a trait, not inherent implementations.
292+
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
293+
debug!(trait_ref = ?trait_ref.skip_binder());
294+
295+
// If the *trait* is local to the crate, ok.
296+
if let Some(def_id) = trait_ref.skip_binder().def_id.as_local() {
297+
debug!("trait {def_id:?} is local to current crate");
298+
return Ok(());
299+
}
300+
301+
// (1) Instantiate all generic params with fresh inference vars.
302+
let infcx = tcx.infer_ctxt().intercrate(true).build();
303+
let cause = traits::ObligationCause::dummy();
304+
let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id());
305+
let trait_ref = trait_ref.instantiate(tcx, args);
306+
307+
let lazily_normalize_ty = |user_ty: Ty<'tcx>| {
308+
let ty::Alias(..) = user_ty.kind() else { return Ok(user_ty) };
309+
310+
let ocx = traits::ObligationCtxt::new(&infcx);
311+
let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), user_ty);
312+
let ty = infcx.resolve_vars_if_possible(ty);
313+
let errors = ocx.select_where_possible();
314+
if !errors.is_empty() {
315+
return Ok(user_ty);
316+
}
317+
318+
let ty = if infcx.next_trait_solver() {
319+
let mut fulfill_cx = <dyn traits::TraitEngine<'_>>::new(&infcx);
320+
infcx
321+
.at(&cause, ty::ParamEnv::empty())
322+
.structurally_normalize(ty, &mut *fulfill_cx)
323+
.map(|ty| infcx.resolve_vars_if_possible(ty))
324+
.unwrap_or(ty)
325+
} else {
326+
ty
327+
};
328+
329+
Ok(ty)
330+
};
331+
332+
let Ok(result) = traits::orphan_check_trait_ref::<!>(
333+
trait_ref,
334+
traits::InCrate::Local { mode },
335+
lazily_normalize_ty,
336+
) else {
337+
unreachable!()
338+
};
339+
340+
// (2) Try to map the remaining inference vars back to generic params.
341+
result.map_err(|err| match err {
342+
OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
343+
let mut collector =
344+
UncoveredTyParamCollector { infcx: &infcx, uncovered_params: Default::default() };
345+
uncovered.visit_with(&mut collector);
346+
// FIXME(fmease): This is very likely reachable.
347+
debug_assert!(!collector.uncovered_params.is_empty());
348+
349+
OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
350+
uncovered: collector.uncovered_params,
351+
local_ty,
352+
})
353+
}
354+
OrphanCheckErr::NonLocalInputType(tys) => {
355+
let generics = tcx.generics_of(impl_def_id);
356+
let tys = tys
357+
.into_iter()
358+
.map(|(ty, is_target_ty)| {
359+
(ty.fold_with(&mut TyVarReplacer { infcx: &infcx, generics }), is_target_ty)
360+
})
361+
.collect();
362+
OrphanCheckErr::NonLocalInputType(tys)
363+
}
364+
})
365+
}
366+
278367
fn emit_orphan_check_error<'tcx>(
279368
tcx: TyCtxt<'tcx>,
280-
sp: Span,
281-
full_impl_span: Span,
282-
trait_span: Span,
283369
trait_ref: ty::TraitRef<'tcx>,
284-
self_ty_span: Span,
285-
generics: &hir::Generics<'tcx>,
286-
err: traits::OrphanCheckErr<'tcx>,
287-
) -> Result<!, ErrorGuaranteed> {
288-
let self_ty = trait_ref.self_ty();
289-
Err(match err {
370+
impl_def_id: LocalDefId,
371+
err: traits::OrphanCheckErr<'tcx, FxIndexSet<DefId>>,
372+
) -> ErrorGuaranteed {
373+
match err {
290374
traits::OrphanCheckErr::NonLocalInputType(tys) => {
291-
let mut diag = tcx.dcx().create_err(match self_ty.kind() {
292-
ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () },
293-
_ if self_ty.is_primitive() => {
294-
errors::OnlyCurrentTraits::Primitive { span: sp, note: () }
375+
let item = tcx.hir().expect_item(impl_def_id);
376+
let impl_ = item.expect_impl();
377+
let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
378+
379+
let span = tcx.def_span(impl_def_id);
380+
let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
381+
ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span, note: () },
382+
_ if trait_ref.self_ty().is_primitive() => {
383+
errors::OnlyCurrentTraits::Primitive { span, note: () }
295384
}
296-
_ => errors::OnlyCurrentTraits::Arbitrary { span: sp, note: () },
385+
_ => errors::OnlyCurrentTraits::Arbitrary { span, note: () },
297386
});
298387

299388
for &(mut ty, is_target_ty) in &tys {
300389
let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
301390
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
302-
self_ty_span
391+
impl_.self_ty.span
303392
} else {
304393
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
305-
trait_span
394+
hir_trait_ref.path.span
306395
};
307396

308397
ty = tcx.erase_regions(ty);
@@ -354,12 +443,12 @@ fn emit_orphan_check_error<'tcx>(
354443
diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span });
355444
}
356445
ty::RawPtr(ptr_ty, mutbl) => {
357-
if !self_ty.has_param() {
446+
if !trait_ref.self_ty().has_param() {
358447
diag.subdiagnostic(
359448
tcx.dcx(),
360449
errors::OnlyCurrentTraitsPointerSugg {
361-
wrapper_span: self_ty_span,
362-
struct_span: full_impl_span.shrink_to_lo(),
450+
wrapper_span: impl_.self_ty.span,
451+
struct_span: item.span.shrink_to_lo(),
363452
mut_key: mutbl.prefix_str(),
364453
ptr_ty,
365454
},
@@ -387,23 +476,112 @@ fn emit_orphan_check_error<'tcx>(
387476

388477
diag.emit()
389478
}
390-
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
391-
let mut sp = sp;
392-
for param in generics.params {
393-
if param.name.ident().to_string() == param_ty.to_string() {
394-
sp = param.span;
395-
}
396-
}
479+
traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
480+
let mut reported = None;
481+
for param_def_id in uncovered {
482+
let span = tcx.def_ident_span(param_def_id).unwrap();
483+
let name = tcx.item_name(param_def_id);
397484

398-
match local_type {
399-
Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
400-
span: sp,
401-
note: (),
402-
param_ty,
403-
local_type,
404-
}),
405-
None => tcx.dcx().emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
485+
reported.get_or_insert(match local_ty {
486+
Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
487+
span,
488+
note: (),
489+
param: name,
490+
local_type,
491+
}),
492+
None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param: name }),
493+
});
406494
}
495+
reported.unwrap() // FIXME(fmease): This is very likely reachable.
407496
}
408-
})
497+
}
498+
}
499+
500+
fn lint_uncovered_ty_params<'tcx>(
501+
tcx: TyCtxt<'tcx>,
502+
UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<'tcx, FxIndexSet<DefId>>,
503+
impl_def_id: LocalDefId,
504+
) {
505+
let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
506+
507+
for param_def_id in uncovered {
508+
let span = tcx.def_ident_span(param_def_id).unwrap();
509+
let name = tcx.item_name(param_def_id);
510+
511+
match local_ty {
512+
Some(local_type) => tcx.emit_node_span_lint(
513+
UNCOVERED_PARAM_IN_PROJECTION,
514+
hir_id,
515+
span,
516+
errors::TyParamFirstLocalLint { span, note: (), param: name, local_type },
517+
),
518+
None => tcx.emit_node_span_lint(
519+
UNCOVERED_PARAM_IN_PROJECTION,
520+
hir_id,
521+
span,
522+
errors::TyParamSomeLint { span, note: (), param: name },
523+
),
524+
};
525+
}
526+
}
527+
528+
struct UncoveredTyParamCollector<'cx, 'tcx> {
529+
infcx: &'cx InferCtxt<'tcx>,
530+
uncovered_params: FxIndexSet<DefId>,
531+
}
532+
533+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
534+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
535+
if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
536+
return;
537+
}
538+
let Some(origin) = self.infcx.type_var_origin(ty) else {
539+
return ty.super_visit_with(self);
540+
};
541+
if let Some(def_id) = origin.param_def_id {
542+
self.uncovered_params.insert(def_id);
543+
}
544+
}
545+
546+
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
547+
if ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
548+
ct.super_visit_with(self)
549+
}
550+
}
551+
}
552+
553+
struct TyVarReplacer<'cx, 'tcx> {
554+
infcx: &'cx InferCtxt<'tcx>,
555+
generics: &'tcx ty::Generics,
556+
}
557+
558+
impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> {
559+
fn interner(&self) -> TyCtxt<'tcx> {
560+
self.infcx.tcx
561+
}
562+
563+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
564+
if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
565+
return ty;
566+
}
567+
let Some(origin) = self.infcx.type_var_origin(ty) else {
568+
return ty.super_fold_with(self);
569+
};
570+
if let Some(def_id) = origin.param_def_id {
571+
// The generics of an `impl` don't have a parent, we can index directly.
572+
let index = self.generics.param_def_id_to_index[&def_id];
573+
let name = self.generics.params[index as usize].name;
574+
575+
Ty::new_param(self.infcx.tcx, index, name)
576+
} else {
577+
ty
578+
}
579+
}
580+
581+
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
582+
if !ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
583+
return ct;
584+
}
585+
ct.super_fold_with(self)
586+
}
409587
}

‎compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,29 +1355,54 @@ pub struct CrossCrateTraitsDefined {
13551355
pub traits: String,
13561356
}
13571357

1358+
// FIXME(fmease): Deduplicate:
1359+
13581360
#[derive(Diagnostic)]
13591361
#[diag(hir_analysis_ty_param_first_local, code = E0210)]
13601362
#[note]
1361-
pub struct TyParamFirstLocal<'a> {
1363+
pub struct TyParamFirstLocal<'tcx> {
13621364
#[primary_span]
13631365
#[label]
13641366
pub span: Span,
13651367
#[note(hir_analysis_case_note)]
13661368
pub note: (),
1367-
pub param_ty: Ty<'a>,
1368-
pub local_type: Ty<'a>,
1369+
pub param: Symbol,
1370+
pub local_type: Ty<'tcx>,
1371+
}
1372+
1373+
#[derive(LintDiagnostic)]
1374+
#[diag(hir_analysis_ty_param_first_local, code = E0210)]
1375+
#[note]
1376+
pub struct TyParamFirstLocalLint<'tcx> {
1377+
#[label]
1378+
pub span: Span,
1379+
#[note(hir_analysis_case_note)]
1380+
pub note: (),
1381+
pub param: Symbol,
1382+
pub local_type: Ty<'tcx>,
13691383
}
13701384

13711385
#[derive(Diagnostic)]
13721386
#[diag(hir_analysis_ty_param_some, code = E0210)]
13731387
#[note]
1374-
pub struct TyParamSome<'a> {
1388+
pub struct TyParamSome {
13751389
#[primary_span]
13761390
#[label]
13771391
pub span: Span,
13781392
#[note(hir_analysis_only_note)]
13791393
pub note: (),
1380-
pub param_ty: Ty<'a>,
1394+
pub param: Symbol,
1395+
}
1396+
1397+
#[derive(LintDiagnostic)]
1398+
#[diag(hir_analysis_ty_param_some, code = E0210)]
1399+
#[note]
1400+
pub struct TyParamSomeLint {
1401+
#[label]
1402+
pub span: Span,
1403+
#[note(hir_analysis_only_note)]
1404+
pub note: (),
1405+
pub param: Symbol,
13811406
}
13821407

13831408
#[derive(Diagnostic)]

‎compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ declare_lint_pass! {
101101
TYVAR_BEHIND_RAW_POINTER,
102102
UNCONDITIONAL_PANIC,
103103
UNCONDITIONAL_RECURSION,
104+
UNCOVERED_PARAM_IN_PROJECTION,
104105
UNDEFINED_NAKED_FUNCTION_ABI,
105106
UNEXPECTED_CFGS,
106107
UNFULFILLED_LINT_EXPECTATIONS,
@@ -4741,3 +4742,68 @@ declare_lint! {
47414742
};
47424743
crate_level_only
47434744
}
4745+
4746+
declare_lint! {
4747+
/// The `uncovered_param_in_projection` lint detects a violation of one of Rust's orphan rules for
4748+
/// foreign trait implementations that concerns the use of type parameters inside trait associated
4749+
/// type paths ("projections") whose output may not be a local type that is mistakenly considered
4750+
/// to "cover" said parameters which is **unsound** and which may be rejected by a future version
4751+
/// of the compiler.
4752+
///
4753+
/// Originally reported in [#99554].
4754+
///
4755+
/// [#99554]: https://github.com/rust-lang/rust/issues/99554
4756+
///
4757+
/// ### Example
4758+
///
4759+
/// ```rust,ignore (dependent)
4760+
/// // dependency.rs
4761+
/// #![crate_type = "lib"]
4762+
///
4763+
/// pub trait Trait<T, U> {}
4764+
/// ```
4765+
///
4766+
/// ```edition2021,ignore (needs dependency)
4767+
/// // dependent.rs
4768+
/// trait Identity {
4769+
/// type Output;
4770+
/// }
4771+
///
4772+
/// impl<T> Identity for T {
4773+
/// type Output = T;
4774+
/// }
4775+
///
4776+
/// struct Local;
4777+
///
4778+
/// impl<T> dependency::Trait<Local, T> for <T as Identity>::Output {}
4779+
///
4780+
/// fn main() {}
4781+
/// ```
4782+
///
4783+
/// This will produce:
4784+
///
4785+
/// ```text
4786+
/// warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
4787+
/// --> dependent.rs:11:6
4788+
/// |
4789+
/// 11 | impl<T> dependency::Trait<Local, T> for <T as Identity>::Output {}
4790+
/// | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
4791+
/// |
4792+
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
4793+
/// = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
4794+
/// = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
4795+
/// = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
4796+
/// = note: `#[warn(uncovered_param_in_projection)]` on by default
4797+
/// ```
4798+
///
4799+
/// ### Explanation
4800+
///
4801+
/// FIXME(fmease): Write explainer.
4802+
pub UNCOVERED_PARAM_IN_PROJECTION,
4803+
Warn,
4804+
"impl contains type parameters that are not covered",
4805+
@future_incompatible = FutureIncompatibleInfo {
4806+
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
4807+
reference: "issue #124559 <https://github.com/rust-lang/rust/issues/124559>",
4808+
};
4809+
}

‎compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 112 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,44 @@ use crate::traits::{
2020
use rustc_data_structures::fx::FxIndexSet;
2121
use rustc_errors::{Diag, EmissionGuarantee};
2222
use rustc_hir::def::DefKind;
23-
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
23+
use rustc_hir::def_id::DefId;
2424
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
2525
use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineExt};
2626
use rustc_middle::traits::query::NoSolution;
2727
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
2828
use rustc_middle::traits::specialization_graph::OverlapMode;
2929
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
30-
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
31-
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
30+
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
31+
use rustc_middle::ty::{self, Ty, TyCtxt};
3232
use rustc_span::symbol::sym;
3333
use rustc_span::{Span, DUMMY_SP};
3434
use std::fmt::Debug;
3535
use std::ops::ControlFlow;
3636

3737
use super::error_reporting::suggest_new_overflow_limit;
3838

39-
/// Whether we do the orphan check relative to this crate or
40-
/// to some remote crate.
39+
/// Whether we do the orphan check relative to this crate or to some remote crate.
4140
#[derive(Copy, Clone, Debug)]
42-
enum InCrate {
43-
Local,
41+
pub enum InCrate {
42+
Local { mode: OrphanCheckMode },
4443
Remote,
4544
}
4645

46+
#[derive(Copy, Clone, Debug)]
47+
pub enum OrphanCheckMode {
48+
/// Proper orphan check.
49+
Proper,
50+
/// Improper orphan check for backward compatibility.
51+
///
52+
/// In this mode, type params inside projections are considered to be covered
53+
/// even if the projection may normalize to a type that doesn't actually cover
54+
/// them. This is unsound. See also [#124559] and [#99554].
55+
///
56+
/// [#124559]: https://github.com/rust-lang/rust/issues/124559
57+
/// [#99554]: https://github.com/rust-lang/rust/issues/99554
58+
Compat,
59+
}
60+
4761
#[derive(Debug, Copy, Clone)]
4862
pub enum Conflict {
4963
Upstream,
@@ -633,7 +647,13 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>(
633647
// and if we are an intermediate owner, then we don't care
634648
// about future-compatibility, which means that we're OK if
635649
// we are an owner.
636-
if orphan_check_trait_ref(trait_ref, InCrate::Local, &mut lazily_normalize_ty)?.is_ok() {
650+
if orphan_check_trait_ref(
651+
trait_ref,
652+
InCrate::Local { mode: OrphanCheckMode::Proper },
653+
&mut lazily_normalize_ty,
654+
)?
655+
.is_ok()
656+
{
637657
Ok(Ok(()))
638658
} else {
639659
Ok(Err(Conflict::Upstream))
@@ -644,7 +664,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>(
644664
tcx: TyCtxt<'tcx>,
645665
trait_ref: ty::TraitRef<'tcx>,
646666
) -> bool {
647-
trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
667+
trait_ref.def_id.is_local() || tcx.has_attr(trait_ref.def_id, sym::fundamental)
648668
}
649669

650670
#[derive(Debug, Copy, Clone)]
@@ -663,31 +683,15 @@ impl From<bool> for IsFirstInputType {
663683
}
664684

665685
#[derive(Debug)]
666-
pub enum OrphanCheckErr<'tcx> {
686+
pub enum OrphanCheckErr<'tcx, T> {
667687
NonLocalInputType(Vec<(Ty<'tcx>, IsFirstInputType)>),
668-
UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>),
688+
UncoveredTyParams(UncoveredTyParams<'tcx, T>),
669689
}
670690

671-
/// Checks the coherence orphan rules. `impl_def_id` should be the
672-
/// `DefId` of a trait impl. To pass, either the trait must be local, or else
673-
/// two conditions must be satisfied:
674-
///
675-
/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
676-
/// 2. Some local type must appear in `Self`.
677-
#[instrument(level = "debug", skip(tcx), ret)]
678-
pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> {
679-
// We only except this routine to be invoked on implementations
680-
// of a trait, not inherent implementations.
681-
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
682-
debug!(?trait_ref);
683-
684-
// If the *trait* is local to the crate, ok.
685-
if trait_ref.def_id.is_local() {
686-
debug!("trait {:?} is local to current crate", trait_ref.def_id);
687-
return Ok(());
688-
}
689-
690-
orphan_check_trait_ref::<!>(trait_ref, InCrate::Local, |ty| Ok(ty)).unwrap()
691+
#[derive(Debug)]
692+
pub struct UncoveredTyParams<'tcx, T> {
693+
pub uncovered: T,
694+
pub local_ty: Option<Ty<'tcx>>,
691695
}
692696

693697
/// Checks whether a trait-ref is potentially implementable by a crate.
@@ -735,6 +739,9 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
735739
/// To check that a local impl follows the orphan rules, we check it in
736740
/// InCrate::Local mode, using type parameters for the "generic" types.
737741
///
742+
/// In InCrate::Local mode the orphan check succeeds if the current crate
743+
/// is definitely allowed to implement the given trait (no false positives).
744+
///
738745
/// 2. They ground negative reasoning for coherence. If a user wants to
739746
/// write both a conditional blanket impl and a specific impl, we need to
740747
/// make sure they do not overlap. For example, if we write
@@ -753,6 +760,9 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
753760
/// try to implement this trait-ref. To check for this, we use InCrate::Remote
754761
/// mode. That is sound because we already know all the impls from known crates.
755762
///
763+
/// In InCrate::Remote mode the orphan check succeeds if a foreign crate
764+
/// *could* implement the given trait (no false negatives).
765+
///
756766
/// 3. For non-`#[fundamental]` traits, they guarantee that parent crates can
757767
/// add "non-blanket" impls without breaking negative reasoning in dependent
758768
/// crates. This is the "rebalancing coherence" (RFC 1023) restriction.
@@ -777,11 +787,11 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
777787
/// Note that this function is never called for types that have both type
778788
/// parameters and inference variables.
779789
#[instrument(level = "trace", skip(lazily_normalize_ty), ret)]
780-
fn orphan_check_trait_ref<'tcx, E: Debug>(
790+
pub fn orphan_check_trait_ref<'tcx, E: Debug>(
781791
trait_ref: ty::TraitRef<'tcx>,
782792
in_crate: InCrate,
783793
lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
784-
) -> Result<Result<(), OrphanCheckErr<'tcx>>, E> {
794+
) -> Result<Result<(), OrphanCheckErr<'tcx, Ty<'tcx>>>, E> {
785795
if trait_ref.has_infer() && trait_ref.has_param() {
786796
bug!(
787797
"can't orphan check a trait ref with both params and inference variables {:?}",
@@ -790,30 +800,36 @@ fn orphan_check_trait_ref<'tcx, E: Debug>(
790800
}
791801

792802
let mut checker = OrphanChecker::new(in_crate, lazily_normalize_ty);
803+
804+
// Does there exist some local type after the `ParamTy`.
805+
let search_first_local_ty = |checker: &mut OrphanChecker<'tcx, _>| {
806+
checker.search_first_local_ty = true;
807+
match trait_ref.visit_with(checker).break_value() {
808+
Some(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty),
809+
_ => None,
810+
}
811+
};
812+
793813
Ok(match trait_ref.visit_with(&mut checker) {
794814
ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
795-
ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)) => return Err(err),
796-
ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
797-
// Does there exist some local type after the `ParamTy`.
798-
checker.search_first_local_ty = true;
799-
if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) =
800-
trait_ref.visit_with(&mut checker).break_value()
801-
{
802-
Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty)))
803-
} else {
804-
Err(OrphanCheckErr::UncoveredTy(ty, None))
815+
ControlFlow::Break(residual) => match residual {
816+
OrphanCheckEarlyExit::NormalizationFailure(err) => return Err(err),
817+
OrphanCheckEarlyExit::UncoveredTyParam(ty) => {
818+
Err(OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
819+
uncovered: ty,
820+
local_ty: search_first_local_ty(&mut checker),
821+
}))
805822
}
806-
}
807-
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()),
823+
OrphanCheckEarlyExit::LocalTy(_) => Ok(()),
824+
},
808825
})
809826
}
810827

811828
struct OrphanChecker<'tcx, F> {
812829
in_crate: InCrate,
813830
in_self_ty: bool,
814831
lazily_normalize_ty: F,
815-
/// Ignore orphan check failures and exclusively search for the first
816-
/// local type.
832+
/// Ignore orphan check failures and exclusively search for the first local type.
817833
search_first_local_ty: bool,
818834
non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>,
819835
}
@@ -837,25 +853,28 @@ where
837853
ControlFlow::Continue(())
838854
}
839855

840-
fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
856+
fn found_uncovered_ty_param(
857+
&mut self,
858+
ty: Ty<'tcx>,
859+
) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
841860
if self.search_first_local_ty {
842-
ControlFlow::Continue(())
843-
} else {
844-
ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t))
861+
return ControlFlow::Continue(());
845862
}
863+
864+
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty))
846865
}
847866

848867
fn def_id_is_local(&mut self, def_id: DefId) -> bool {
849868
match self.in_crate {
850-
InCrate::Local => def_id.is_local(),
869+
InCrate::Local { .. } => def_id.is_local(),
851870
InCrate::Remote => false,
852871
}
853872
}
854873
}
855874

856875
enum OrphanCheckEarlyExit<'tcx, E> {
857876
NormalizationFailure(E),
858-
ParamTy(Ty<'tcx>),
877+
UncoveredTyParam(Ty<'tcx>),
859878
LocalTy(Ty<'tcx>),
860879
}
861880

@@ -864,14 +883,15 @@ where
864883
F: FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
865884
{
866885
type Result = ControlFlow<OrphanCheckEarlyExit<'tcx, E>>;
886+
867887
fn visit_region(&mut self, _r: ty::Region<'tcx>) -> Self::Result {
868888
ControlFlow::Continue(())
869889
}
870890

871891
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
872-
// Need to lazily normalize here in with `-Znext-solver=coherence`.
873892
let ty = match (self.lazily_normalize_ty)(ty) {
874-
Ok(ty) => ty,
893+
Ok(norm_ty) if norm_ty.is_ty_var() => ty,
894+
Ok(norm_ty) => norm_ty,
875895
Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)),
876896
};
877897

@@ -889,19 +909,46 @@ where
889909
| ty::Slice(..)
890910
| ty::RawPtr(..)
891911
| ty::Never
892-
| ty::Tuple(..)
893-
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => {
894-
self.found_non_local_ty(ty)
912+
| ty::Tuple(..) => self.found_non_local_ty(ty),
913+
914+
ty::Param(..) => bug!("unexpected ty param"),
915+
916+
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => {
917+
match self.in_crate {
918+
InCrate::Local { .. } => self.found_uncovered_ty_param(ty),
919+
// The inference variable might be unified with a local
920+
// type in that remote crate.
921+
InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
922+
}
895923
}
896924

897-
ty::Param(..) => self.found_param_ty(ty),
925+
ty::Alias(kind @ (ty::Projection | ty::Inherent | ty::Weak), ..) => {
926+
if ty.has_type_flags(ty::TypeFlags::HAS_TY_PARAM) {
927+
bug!("unexpected ty param in alias ty");
928+
}
898929

899-
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate {
900-
InCrate::Local => self.found_non_local_ty(ty),
901-
// The inference variable might be unified with a local
902-
// type in that remote crate.
903-
InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
904-
},
930+
if ty.has_type_flags(
931+
ty::TypeFlags::HAS_TY_PLACEHOLDER
932+
| ty::TypeFlags::HAS_TY_BOUND
933+
| ty::TypeFlags::HAS_TY_INFER,
934+
) {
935+
match self.in_crate {
936+
InCrate::Local { mode } => match kind {
937+
ty::Projection if let OrphanCheckMode::Compat = mode => {
938+
ControlFlow::Continue(())
939+
}
940+
_ => self.found_uncovered_ty_param(ty),
941+
},
942+
InCrate::Remote => {
943+
// The inference variable might be unified with a local
944+
// type in that remote crate.
945+
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
946+
}
947+
}
948+
} else {
949+
ControlFlow::Continue(())
950+
}
951+
}
905952

906953
// For fundamental types, we just look inside of them.
907954
ty::Ref(_, ty, _) => ty.visit_with(self),

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ use rustc_span::Span;
4141
use std::fmt::Debug;
4242
use std::ops::ControlFlow;
4343

44-
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
45-
pub use self::coherence::{IsFirstInputType, OrphanCheckErr, OverlapResult};
44+
pub use self::coherence::{add_placeholder_note, orphan_check_trait_ref, overlapping_impls};
45+
pub use self::coherence::{InCrate, IsFirstInputType, UncoveredTyParams};
46+
pub use self::coherence::{OrphanCheckErr, OrphanCheckMode, OverlapResult};
4647
pub use self::engine::{ObligationCtxt, TraitEngineExt};
4748
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
4849
pub use self::normalize::NormalizeExt;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub trait Trait0<T, U, V> {}
2+
pub trait Trait1<T, U> {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub trait Trait {
2+
type Assoc;
3+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>`
2+
--> $DIR/coherence-overlap-unnormalizable-projection-0.rs:27:1
3+
|
4+
LL | / impl<T> Trait for T
5+
LL | | where
6+
LL | | T: 'static,
7+
LL | | for<'a> T: WithAssoc<'a>,
8+
LL | | for<'a> <T as WithAssoc<'a>>::Assoc: WhereBound,
9+
| |____________________________________________________- first implementation here
10+
...
11+
LL | impl<T> Trait for Box<T> {}
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
13+
|
14+
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
15+
= note: downstream crates may implement trait `WhereBound` for type `<std::boxed::Box<_> as WithAssoc<'a>>::Assoc`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0119`.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>`
2+
--> $DIR/coherence-overlap-unnormalizable-projection-0.rs:27:1
3+
|
4+
LL | / impl<T> Trait for T
5+
LL | | where
6+
LL | | T: 'static,
7+
LL | | for<'a> T: WithAssoc<'a>,
8+
LL | | for<'a> <T as WithAssoc<'a>>::Assoc: WhereBound,
9+
| |____________________________________________________- first implementation here
10+
...
11+
LL | impl<T> Trait for Box<T> {}
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
13+
|
14+
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0119`.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Regression test for soundness issue #114061:
2+
// "Coherence incorrectly considers `unnormalizable_projection: Trait` to not hold even if it could"
3+
#![crate_type = "lib"]
4+
5+
//@ revisions: classic next
6+
//@[next] compile-flags: -Znext-solver
7+
8+
trait WhereBound {}
9+
impl WhereBound for () {}
10+
11+
12+
pub trait WithAssoc<'a> {
13+
type Assoc;
14+
}
15+
16+
// These two impls of `Trait` overlap:
17+
18+
pub trait Trait {}
19+
impl<T> Trait for T
20+
where
21+
T: 'static,
22+
for<'a> T: WithAssoc<'a>,
23+
for<'a> <T as WithAssoc<'a>>::Assoc: WhereBound,
24+
{
25+
}
26+
27+
impl<T> Trait for Box<T> {} //~ ERROR conflicting implementations of trait `Trait` for type `Box<_>`
28+
29+
// A downstream crate could write:
30+
//
31+
// use upstream::*;
32+
//
33+
// struct Local;
34+
// impl WithAssoc<'_> for Box<Local> {
35+
// type Assoc = ();
36+
// }
37+
//
38+
// fn impls_trait<T: Trait>() {}
39+
//
40+
// fn main() {
41+
// impls_trait::<Box<Local>>();
42+
// }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>`
2+
--> $DIR/coherence-overlap-unnormalizable-projection-1.rs:26:1
3+
|
4+
LL | / impl<T> Trait for T
5+
LL | | where
6+
LL | | T: 'static,
7+
LL | | for<'a> T: WithAssoc<'a>,
8+
LL | | for<'a> Box<<T as WithAssoc<'a>>::Assoc>: WhereBound,
9+
| |_________________________________________________________- first implementation here
10+
...
11+
LL | impl<T> Trait for Box<T> {}
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
13+
|
14+
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
15+
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0119`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0119]: conflicting implementations of trait `Trait` for type `Box<_>`
2+
--> $DIR/coherence-overlap-unnormalizable-projection-1.rs:26:1
3+
|
4+
LL | / impl<T> Trait for T
5+
LL | | where
6+
LL | | T: 'static,
7+
LL | | for<'a> T: WithAssoc<'a>,
8+
LL | | for<'a> Box<<T as WithAssoc<'a>>::Assoc>: WhereBound,
9+
| |_________________________________________________________- first implementation here
10+
...
11+
LL | impl<T> Trait for Box<T> {}
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
13+
|
14+
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
15+
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0119`.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Regression test for soundness issue #114061:
2+
// "Coherence incorrectly considers `unnormalizable_projection: Trait` to not hold even if it could"
3+
#![crate_type = "lib"]
4+
5+
//@ revisions: classic next
6+
//@[next] compile-flags: -Znext-solver
7+
8+
pub trait WhereBound {}
9+
impl WhereBound for () {}
10+
11+
pub trait WithAssoc<'a> {
12+
type Assoc;
13+
}
14+
15+
// These two impls of `Trait` overlap:
16+
17+
pub trait Trait {}
18+
impl<T> Trait for T
19+
where
20+
T: 'static,
21+
for<'a> T: WithAssoc<'a>,
22+
for<'a> Box<<T as WithAssoc<'a>>::Assoc>: WhereBound,
23+
{
24+
}
25+
26+
impl<T> Trait for Box<T> {} //~ ERROR conflicting implementations of trait `Trait` for type `Box<_>`
27+
28+
// A downstream crate could write:
29+
//
30+
//
31+
// use upstream::*;
32+
//
33+
// struct Local;
34+
// impl WithAssoc<'_> for Box<Local> {
35+
// type Assoc = Local;
36+
// }
37+
//
38+
// impl WhereBound for Box<Local> {}
39+
//
40+
// fn impls_trait<T: Trait>() {}
41+
//
42+
// fn main() {
43+
// impls_trait::<Box<Local>>();
44+
// }
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Projections cover type parameters if they normalize to a (local) type that covers them.
2+
// This ensures that we don't perform an overly strict check on
3+
// projections like in closed PR #100555 which did a syntactic
4+
// check for type parameters in projections without normalizing
5+
// first which would've lead to real-word regressions.
6+
7+
//@ check-pass
8+
//@ revisions: classic next
9+
//@[next] compile-flags: -Znext-solver
10+
11+
//@ aux-crate:foreign=parametrized-trait.rs
12+
//@ edition:2021
13+
14+
trait Project { type Output; }
15+
16+
impl<T> Project for Wrapper<T> {
17+
type Output = Local;
18+
}
19+
20+
struct Wrapper<T>(T);
21+
struct Local;
22+
23+
impl<T> foreign::Trait1<Local, T> for <Wrapper<T> as Project>::Output {}
24+
25+
fn main() {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// This used to ICE in an earlier iteration of #117164. Minimized from crate `proqnt`.
2+
3+
//@ check-pass
4+
//@ revisions: classic next
5+
//@[next] compile-flags: -Znext-solver
6+
//@ aux-crate:dep=trait-with-assoc-ty.rs
7+
//@ edition: 2021
8+
9+
pub(crate) trait Trait<T> {
10+
type Assoc;
11+
}
12+
13+
pub(crate) struct Type<T, U, V>(T, U, V);
14+
15+
impl<T, U> dep::Trait for Type<T, <<T as dep::Trait>::Assoc as Trait<U>>::Assoc, U>
16+
where
17+
T: dep::Trait,
18+
<T as dep::Trait>::Assoc: Trait<U>,
19+
{
20+
type Assoc = U;
21+
}
22+
23+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-projections-not-covering-ambiguity.rs:25:6
3+
|
4+
LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning: 1 warning emitted
14+
15+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-projections-not-covering-ambiguity.rs:25:6
3+
|
4+
LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning: 1 warning emitted
14+
15+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// This test demonstrates a limitation of the trait solver.
2+
// Basically, one might think that `T` was covered by the projection since the
3+
// latter appears to normalize to a local type. However, since we instantiate the
4+
// constituent types of the self type of impls with fresh infer vars and try to
5+
// normalize them during orphan checking, we wind up trying to normalize a
6+
// projection whose self type is an infer var which unconditionally fails due to
7+
// ambiguity.
8+
9+
//@ revisions: classic next
10+
//@[next] compile-flags: -Znext-solver
11+
12+
//@ check-pass
13+
//@ compile-flags: --crate-type=lib
14+
//@ aux-crate:foreign=parametrized-trait.rs
15+
//@ edition:2021
16+
17+
trait Project { type Output; }
18+
19+
impl<T> Project for T {
20+
type Output = Local;
21+
}
22+
23+
struct Local;
24+
25+
impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
26+
//~^ WARNING type parameter `T` must be covered by another type
27+
//~| WARNING this was previously accepted by the compiler
28+
29+
fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
2+
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:6
3+
|
4+
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
14+
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9
15+
|
16+
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
17+
| ^ type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
18+
|
19+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
20+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
21+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
22+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
23+
24+
warning: 2 warnings emitted
25+
26+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
2+
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:6
3+
|
4+
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
14+
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9
15+
|
16+
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
17+
| ^ type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
18+
|
19+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
20+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
21+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
22+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
23+
24+
warning: 2 warnings emitted
25+
26+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ revisions: classic next
2+
//@[next] compile-flags: -Znext-solver
3+
4+
//@ check-pass
5+
//@ compile-flags: --crate-type=lib
6+
//@ aux-crate:foreign=parametrized-trait.rs
7+
//@ edition:2021
8+
9+
trait Trait<T, U> { type Assoc; }
10+
11+
impl<T, U> Trait<T, U> for () {
12+
type Assoc = LocalTy;
13+
}
14+
15+
struct LocalTy;
16+
17+
impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
18+
//~^ WARNING type parameter `T` must be covered by another type
19+
//~| WARNING this was previously accepted by the compiler
20+
//~| WARNING type parameter `U` must be covered by another type
21+
//~| WARNING this was previously accepted by the compiler
22+
23+
24+
fn main() {}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-projections-not-covering.rs:22:6
3+
|
4+
LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
14+
--> $DIR/orphan-check-projections-not-covering.rs:27:6
15+
|
16+
LL | impl<T> foreign::Trait0<<T as Identity>::Output, Local, T> for Option<T> {}
17+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
18+
|
19+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
20+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
21+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
22+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
23+
24+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
25+
--> $DIR/orphan-check-projections-not-covering.rs:40:6
26+
|
27+
LL | impl<T: Deferred> foreign::Trait1<Local, T> for <T as Deferred>::Output {}
28+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
29+
|
30+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
31+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
32+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
33+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
34+
35+
warning: 3 warnings emitted
36+
37+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-projections-not-covering.rs:22:6
3+
|
4+
LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
14+
--> $DIR/orphan-check-projections-not-covering.rs:27:6
15+
|
16+
LL | impl<T> foreign::Trait0<<T as Identity>::Output, Local, T> for Option<T> {}
17+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
18+
|
19+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
20+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
21+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
22+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
23+
24+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
25+
--> $DIR/orphan-check-projections-not-covering.rs:40:6
26+
|
27+
LL | impl<T: Deferred> foreign::Trait1<Local, T> for <T as Deferred>::Output {}
28+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
29+
|
30+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
31+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
32+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
33+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
34+
35+
warning: 3 warnings emitted
36+
37+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Regression test for issue #99554.
2+
// Projections might not cover type parameters.
3+
4+
//@ revisions: classic next
5+
//@[next] compile-flags: -Znext-solver
6+
7+
//@ check-pass
8+
//@ compile-flags: --crate-type=lib
9+
//@ aux-crate:foreign=parametrized-trait.rs
10+
//@ edition:2021
11+
12+
trait Identity {
13+
type Output;
14+
}
15+
16+
impl<T> Identity for T {
17+
type Output = T;
18+
}
19+
20+
struct Local;
21+
22+
impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
23+
//~^ WARNING type parameter `T` must be covered by another type
24+
//~| WARNING this was previously accepted by the compiler
25+
26+
27+
impl<T> foreign::Trait0<<T as Identity>::Output, Local, T> for Option<T> {}
28+
//~^ WARNING type parameter `T` must be covered by another type
29+
//~| WARNING this was previously accepted by the compiler
30+
31+
pub trait Deferred {
32+
type Output;
33+
}
34+
35+
// A downstream user could implement
36+
//
37+
// impl<T> Deferred for Type<T> { type Output = T; }
38+
// struct Type<T>(T);
39+
//
40+
impl<T: Deferred> foreign::Trait1<Local, T> for <T as Deferred>::Output {}
41+
//~^ WARNING type parameter `T` must be covered by another type
42+
//~| WARNING this was previously accepted by the compiler
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
2+
--> $DIR/orphan-check-projections-unsat-bounds.rs:28:6
3+
|
4+
LL | impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning: 1 warning emitted
14+
15+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
2+
--> $DIR/orphan-check-projections-unsat-bounds.rs:28:6
3+
|
4+
LL | impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
9+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
10+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
11+
= note: `#[warn(uncovered_param_in_projection)]` on by default
12+
13+
warning: 1 warning emitted
14+
15+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// This used to ICE in an earlier iteration of #117164.
2+
// The normalization performed during orphan checking happens inside an empty ParamEnv and
3+
// with type parameters mapped to fresh infer vars. Therefore it may fail for example due to
4+
// unsatisfied bounds while normalization outside of orphan checking succeeds.
5+
6+
//@ revisions: classic next
7+
//@[next] compile-flags: -Znext-solver
8+
9+
//@ check-pass
10+
//@ aux-crate:foreign=parametrized-trait.rs
11+
//@ edition:2021
12+
13+
struct Wrapper<T>(T);
14+
15+
trait Bound {}
16+
17+
trait Discard { type Output; }
18+
19+
impl<T> Discard for Wrapper<T>
20+
where
21+
Wrapper<T>: Bound
22+
{
23+
type Output = LocalTy;
24+
}
25+
26+
struct LocalTy;
27+
28+
impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
29+
//~^ WARNING type parameter `T` must be covered by another type
30+
//~| WARNING this was previously accepted by the compiler
31+
where
32+
Wrapper<T>: Bound
33+
{}
34+
35+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Weak aliases cover type parameters if they normalize to a (local) type that covers them.
2+
3+
//@ check-pass
4+
//@ revisions: classic next
5+
//@[next] compile-flags: -Znext-solver
6+
7+
//@ aux-crate:foreign=parametrized-trait.rs
8+
//@ edition:2021
9+
10+
#![feature(lazy_type_alias)]
11+
#![allow(incomplete_features)]
12+
13+
type Alias<T> = LocalWrapper<T>;
14+
15+
struct Local;
16+
struct LocalWrapper<T>(T);
17+
18+
impl<T> foreign::Trait1<Local, T> for Alias<T> {}
19+
20+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-weak-aliases-not-covering.rs:16:6
3+
|
4+
LL | impl<T> foreign::Trait1<Local, T> for Identity<T> {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2+
--> $DIR/orphan-check-weak-aliases-not-covering.rs:16:6
3+
|
4+
LL | impl<T> foreign::Trait1<Local, T> for Identity<T> {}
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Weak aliases might not cover type parameters.
2+
3+
//@ revisions: classic next
4+
//@[next] compile-flags: -Znext-solver
5+
6+
//@ aux-crate:foreign=parametrized-trait.rs
7+
//@ edition:2021
8+
9+
#![feature(lazy_type_alias)]
10+
#![allow(incomplete_features)]
11+
12+
type Identity<T> = T;
13+
14+
struct Local;
15+
16+
impl<T> foreign::Trait1<Local, T> for Identity<T> {}
17+
//~^ ERROR type parameter `T` must be covered by another type
18+
19+
fn main() {}

‎tests/ui/type-alias-impl-trait/coherence.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar
44
LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {}
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------
66
| | |
7-
| | `AliasOfForeignType<()>` is not defined in the current crate
7+
| | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
88
| impl doesn't use only types from inside the current crate
99
|
1010
= note: define and implement a trait or new type instead

0 commit comments

Comments
 (0)
Please sign in to comment.