diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e7cef9e198b..83ab761aa55 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -748,6 +748,13 @@ pub struct TraitPredicate<'tcx> { pub constness: BoundConstness, + /// If polarity is Positive: we are proving that the trait is implemented. + /// + /// If polarity is Negative: we are proving that a negative impl of this trait + /// exists. (Note that coherence also checks whether negative impls of supertraits + /// exist via a series of predicates.) + /// + /// If polarity is Reserved: that's a bug. pub polarity: ImplPolarity, } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 91695257137..d5b1aa00e52 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1129,7 +1129,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } for param in &generics.params { - if let GenericParamKind::Lifetime { .. } = param.kind { + if let GenericParamKind::Lifetime = param.kind { continue; } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index a3d32acc6fb..94a4001bbb9 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -17,8 +17,8 @@ use crate::traits::{ use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::CRATE_HIR_ID; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngine; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::{util, TraitEngine}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{self, TreatParams}; use rustc_middle::ty::fold::TypeFoldable; @@ -353,6 +353,8 @@ fn negative_impl<'cx, 'tcx>( }) } +/// Try to prove that a negative impl exist for the given obligation and their super predicates. +#[instrument(level = "debug", skip(selcx))] fn negative_impl_exists<'cx, 'tcx>( selcx: &SelectionContext<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -360,42 +362,66 @@ fn negative_impl_exists<'cx, 'tcx>( o: &PredicateObligation<'tcx>, ) -> bool { let infcx = &selcx.infcx().fork(); + + if resolve_negative_obligation(infcx, param_env, region_context, o) { + return true; + } + + // Try to prove a negative obligation exist for super predicates + for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) { + if resolve_negative_obligation(infcx, param_env, region_context, &o) { + return true; + } + } + + false +} + +#[instrument(level = "debug", skip(infcx))] +fn resolve_negative_obligation<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + region_context: DefId, + o: &PredicateObligation<'tcx>, +) -> bool { let tcx = infcx.tcx; - o.flip_polarity(tcx) - .map(|o| { - let mut fulfillment_cx = FulfillmentContext::new(); - fulfillment_cx.register_predicate_obligation(infcx, o); - let errors = fulfillment_cx.select_all_or_error(infcx); - if !errors.is_empty() { - return false; - } + let Some(o) = o.flip_polarity(tcx) else { + return false; + }; - let mut outlives_env = OutlivesEnvironment::new(param_env); - // FIXME -- add "assumed to be well formed" types into the `outlives_env` + let mut fulfillment_cx = FulfillmentContext::new(); + fulfillment_cx.register_predicate_obligation(infcx, o); - // "Save" the accumulated implied bounds into the outlives environment - // (due to the FIXME above, there aren't any, but this step is still needed). - // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used - // by the "dummy" causes elsewhere (body-id is only relevant when checking - // function bodies with closures). - outlives_env.save_implied_bounds(CRATE_HIR_ID); + let errors = fulfillment_cx.select_all_or_error(infcx); - infcx.process_registered_region_obligations( - outlives_env.region_bound_pairs_map(), - Some(tcx.lifetimes.re_root_empty), - param_env, - ); + if !errors.is_empty() { + return false; + } - let errors = - infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default()); - if !errors.is_empty() { - return false; - } + let mut outlives_env = OutlivesEnvironment::new(param_env); + // FIXME -- add "assumed to be well formed" types into the `outlives_env` - true - }) - .unwrap_or(false) + // "Save" the accumulated implied bounds into the outlives environment + // (due to the FIXME above, there aren't any, but this step is still needed). + // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used + // by the "dummy" causes elsewhere (body-id is only relevant when checking + // function bodies with closures). + outlives_env.save_implied_bounds(CRATE_HIR_ID); + + infcx.process_registered_region_obligations( + outlives_env.region_bound_pairs_map(), + Some(tcx.lifetimes.re_root_empty), + param_env, + ); + + let errors = infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default()); + + if !errors.is_empty() { + return false; + } + + true } pub fn trait_ref_is_knowable<'tcx>( diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index b0f052e6cf0..d78fc6d2083 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.8.1 --unsafe-perm=true +RUN npm install -g browser-ui-test@0.8.3 --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh index bb48fcb5a21..c046a6c8a26 100755 --- a/src/ci/scripts/should-skip-this.sh +++ b/src/ci/scripts/should-skip-this.sh @@ -25,6 +25,7 @@ if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then elif ! (git diff --quiet "$BASE_COMMIT" -- \ src/test/rustdoc-gui \ src/librustdoc \ + src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile \ src/tools/rustdoc-gui); then # There was a change in either rustdoc or in its GUI tests. echo "Rustdoc was updated" diff --git a/src/test/ui/coherence/coherence-overlap-double-negative.rs b/src/test/ui/coherence/coherence-overlap-double-negative.rs new file mode 100644 index 00000000000..1ea0ddc7430 --- /dev/null +++ b/src/test/ui/coherence/coherence-overlap-double-negative.rs @@ -0,0 +1,12 @@ +// check-pass + +#![feature(negative_impls)] +#![feature(with_negative_coherence)] + +trait A {} +trait B: A {} + +impl !A for u32 {} +impl !B for u32 {} + +fn main() {} diff --git a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs index c240a183982..48dffc921a3 100644 --- a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs +++ b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs @@ -1,3 +1,5 @@ +// check-pass + #![feature(negative_impls)] #![feature(rustc_attrs)] #![feature(trait_alias)] @@ -13,7 +15,5 @@ impl !A for u32 {} trait C {} impl C for T {} impl C for u32 {} -//~^ ERROR: conflicting implementations of trait `C` for type `u32` [E0119] -// FIXME this should work, we should implement an `assemble_neg_candidates` fn fn main() {} diff --git a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr deleted file mode 100644 index 30d837a5c50..00000000000 --- a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0119]: conflicting implementations of trait `C` for type `u32` - --> $DIR/coherence-overlap-negate-alias-strict.rs:15:1 - | -LL | impl C for T {} - | ------------------- first implementation here -LL | impl C for u32 {} - | ^^^^^^^^^^^^^^ conflicting implementation for `u32` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-overlap-super-negative.rs b/src/test/ui/coherence/coherence-overlap-super-negative.rs new file mode 100644 index 00000000000..d296a094a37 --- /dev/null +++ b/src/test/ui/coherence/coherence-overlap-super-negative.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(negative_impls)] +#![feature(rustc_attrs)] +#![feature(with_negative_coherence)] + +trait Trait1: Trait2 {} +trait Trait2 {} + +struct MyType {} +impl !Trait2 for MyType {} + +#[rustc_strict_coherence] +trait Foo {} +impl Foo for T {} +impl Foo for MyType {} + +fn main() {} diff --git a/src/tools/miri b/src/tools/miri index 7bc0c986217..8e818ffa1b8 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 7bc0c986217629e6c831edcb133532023a5aec63 +Subproject commit 8e818ffa1b85f4e740c4096fd38c62b2b73f4d83