Don't treat closures from other crates as local
This commit is contained in:
parent
481725984b
commit
42f1f54a5e
5 changed files with 58 additions and 24 deletions
|
@ -401,12 +401,12 @@ fn resolve_negative_obligation<'tcx>(
|
||||||
infcx.resolve_regions(&outlives_env).is_empty()
|
infcx.resolve_regions(&outlives_env).is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(tcx), ret)]
|
||||||
pub fn trait_ref_is_knowable<'tcx>(
|
pub fn trait_ref_is_knowable<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
) -> Result<(), Conflict> {
|
) -> Result<(), Conflict> {
|
||||||
debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
|
if orphan_check_trait_ref(trait_ref, InCrate::Remote).is_ok() {
|
||||||
if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() {
|
|
||||||
// A downstream or cousin crate is allowed to implement some
|
// A downstream or cousin crate is allowed to implement some
|
||||||
// substitution of this trait-ref.
|
// substitution of this trait-ref.
|
||||||
return Err(Conflict::Downstream);
|
return Err(Conflict::Downstream);
|
||||||
|
@ -429,11 +429,9 @@ pub fn trait_ref_is_knowable<'tcx>(
|
||||||
// and if we are an intermediate owner, then we don't care
|
// and if we are an intermediate owner, then we don't care
|
||||||
// about future-compatibility, which means that we're OK if
|
// about future-compatibility, which means that we're OK if
|
||||||
// we are an owner.
|
// we are an owner.
|
||||||
if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() {
|
if orphan_check_trait_ref(trait_ref, InCrate::Local).is_ok() {
|
||||||
debug!("trait_ref_is_knowable: orphan check passed");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned");
|
|
||||||
Err(Conflict::Upstream)
|
Err(Conflict::Upstream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,6 +443,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>(
|
||||||
trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
|
trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum OrphanCheckErr<'tcx> {
|
pub enum OrphanCheckErr<'tcx> {
|
||||||
NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>),
|
NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>),
|
||||||
UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>),
|
UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>),
|
||||||
|
@ -456,13 +455,12 @@ pub enum OrphanCheckErr<'tcx> {
|
||||||
///
|
///
|
||||||
/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
|
/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
|
||||||
/// 2. Some local type must appear in `Self`.
|
/// 2. Some local type must appear in `Self`.
|
||||||
|
#[instrument(level = "debug", skip(tcx), ret)]
|
||||||
pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> {
|
pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> {
|
||||||
debug!("orphan_check({:?})", impl_def_id);
|
|
||||||
|
|
||||||
// We only except this routine to be invoked on implementations
|
// We only except this routine to be invoked on implementations
|
||||||
// of a trait, not inherent implementations.
|
// of a trait, not inherent implementations.
|
||||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
|
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
|
||||||
debug!("orphan_check: trait_ref={:?}", trait_ref);
|
debug!(?trait_ref);
|
||||||
|
|
||||||
// If the *trait* is local to the crate, ok.
|
// If the *trait* is local to the crate, ok.
|
||||||
if trait_ref.def_id.is_local() {
|
if trait_ref.def_id.is_local() {
|
||||||
|
@ -470,7 +468,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
orphan_check_trait_ref(tcx, trait_ref, InCrate::Local)
|
orphan_check_trait_ref(trait_ref, InCrate::Local)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether a trait-ref is potentially implementable by a crate.
|
/// Checks whether a trait-ref is potentially implementable by a crate.
|
||||||
|
@ -559,13 +557,11 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
|
||||||
///
|
///
|
||||||
/// Note that this function is never called for types that have both type
|
/// Note that this function is never called for types that have both type
|
||||||
/// parameters and inference variables.
|
/// parameters and inference variables.
|
||||||
|
#[instrument(level = "trace", ret)]
|
||||||
fn orphan_check_trait_ref<'tcx>(
|
fn orphan_check_trait_ref<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
in_crate: InCrate,
|
in_crate: InCrate,
|
||||||
) -> Result<(), OrphanCheckErr<'tcx>> {
|
) -> Result<(), OrphanCheckErr<'tcx>> {
|
||||||
debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate);
|
|
||||||
|
|
||||||
if trait_ref.needs_infer() && trait_ref.needs_subst() {
|
if trait_ref.needs_infer() && trait_ref.needs_subst() {
|
||||||
bug!(
|
bug!(
|
||||||
"can't orphan check a trait ref with both params and inference variables {:?}",
|
"can't orphan check a trait ref with both params and inference variables {:?}",
|
||||||
|
@ -573,7 +569,7 @@ fn orphan_check_trait_ref<'tcx>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut checker = OrphanChecker::new(tcx, in_crate);
|
let mut checker = OrphanChecker::new(in_crate);
|
||||||
match trait_ref.visit_with(&mut checker) {
|
match trait_ref.visit_with(&mut checker) {
|
||||||
ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
|
ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
|
||||||
ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
|
ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
|
||||||
|
@ -592,7 +588,6 @@ fn orphan_check_trait_ref<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OrphanChecker<'tcx> {
|
struct OrphanChecker<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
in_crate: InCrate,
|
in_crate: InCrate,
|
||||||
in_self_ty: bool,
|
in_self_ty: bool,
|
||||||
/// Ignore orphan check failures and exclusively search for the first
|
/// Ignore orphan check failures and exclusively search for the first
|
||||||
|
@ -602,9 +597,8 @@ struct OrphanChecker<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> OrphanChecker<'tcx> {
|
impl<'tcx> OrphanChecker<'tcx> {
|
||||||
fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self {
|
fn new(in_crate: InCrate) -> Self {
|
||||||
OrphanChecker {
|
OrphanChecker {
|
||||||
tcx,
|
|
||||||
in_crate,
|
in_crate,
|
||||||
in_self_ty: true,
|
in_self_ty: true,
|
||||||
search_first_local_ty: false,
|
search_first_local_ty: false,
|
||||||
|
@ -697,13 +691,17 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
|
ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
|
||||||
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
|
ty::Closure(did, ..) | ty::Generator(did, ..) => {
|
||||||
self.tcx.sess.delay_span_bug(
|
if self.def_id_is_local(did) {
|
||||||
DUMMY_SP,
|
|
||||||
format!("ty_is_local invoked on closure or generator: {:?}", ty),
|
|
||||||
);
|
|
||||||
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
|
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
|
||||||
|
} else {
|
||||||
|
self.found_non_local_ty(ty)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// This should only be created when checking whether we have to check whether some
|
||||||
|
// auto trait impl applies. There will never be multiple impls, so we can just
|
||||||
|
// act as if it were a local type here.
|
||||||
|
ty::GeneratorWitness(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
|
||||||
ty::Alias(ty::Opaque, ..) => {
|
ty::Alias(ty::Opaque, ..) => {
|
||||||
// This merits some explanation.
|
// This merits some explanation.
|
||||||
// Normally, opaque types are not involved when performing
|
// Normally, opaque types are not involved when performing
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
// Test that encountering closures during coherence does not cause issues.
|
// Test that encountering closures during coherence does not cause issues.
|
||||||
#![feature(type_alias_impl_trait, generators)]
|
#![feature(type_alias_impl_trait, generators)]
|
||||||
|
#![cfg_attr(specialized, feature(specialization))]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// revisions: stock specialized
|
||||||
|
// [specialized]check-pass
|
||||||
|
|
||||||
type OpaqueGenerator = impl Sized;
|
type OpaqueGenerator = impl Sized;
|
||||||
fn defining_use() -> OpaqueGenerator {
|
fn defining_use() -> OpaqueGenerator {
|
||||||
|| {
|
|| {
|
||||||
|
@ -13,6 +19,6 @@ struct Wrapper<T>(T);
|
||||||
trait Trait {}
|
trait Trait {}
|
||||||
impl Trait for Wrapper<OpaqueGenerator> {}
|
impl Trait for Wrapper<OpaqueGenerator> {}
|
||||||
impl<T: Sync> Trait for Wrapper<T> {}
|
impl<T: Sync> Trait for Wrapper<T> {}
|
||||||
//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
|
//[stock]~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
|
error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
|
||||||
--> $DIR/coherence-with-generator.rs:15:1
|
--> $DIR/coherence-with-generator.rs:21:1
|
||||||
|
|
|
|
||||||
LL | impl Trait for Wrapper<OpaqueGenerator> {}
|
LL | impl Trait for Wrapper<OpaqueGenerator> {}
|
||||||
| --------------------------------------- first implementation here
|
| --------------------------------------- first implementation here
|
19
tests/ui/type-alias-impl-trait/issue-104817.rs
Normal file
19
tests/ui/type-alias-impl-trait/issue-104817.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![cfg_attr(specialized, feature(specialization))]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
// revisions: stock specialized
|
||||||
|
// [specialized]check-pass
|
||||||
|
|
||||||
|
trait OpaqueTrait {}
|
||||||
|
impl<T> OpaqueTrait for T {}
|
||||||
|
type OpaqueType = impl OpaqueTrait;
|
||||||
|
fn mk_opaque() -> OpaqueType {
|
||||||
|
|| 0
|
||||||
|
}
|
||||||
|
trait AnotherTrait {}
|
||||||
|
impl<T: Send> AnotherTrait for T {}
|
||||||
|
impl AnotherTrait for OpaqueType {}
|
||||||
|
//[stock]~^ conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
|
||||||
|
|
||||||
|
fn main() {}
|
11
tests/ui/type-alias-impl-trait/issue-104817.stock.stderr
Normal file
11
tests/ui/type-alias-impl-trait/issue-104817.stock.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
|
||||||
|
--> $DIR/issue-104817.rs:16:1
|
||||||
|
|
|
||||||
|
LL | impl<T: Send> AnotherTrait for T {}
|
||||||
|
| -------------------------------- first implementation here
|
||||||
|
LL | impl AnotherTrait for OpaqueType {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
Loading…
Add table
Add a link
Reference in a new issue