From 05dcb7874a5a8c84fe943dcbae12010ba5a40c25 Mon Sep 17 00:00:00 2001 From: Ellen Date: Wed, 23 Jun 2021 18:18:32 +0100 Subject: [PATCH 01/22] Dont provide all parent generics to cgdefaults --- compiler/rustc_middle/src/ty/consts.rs | 33 +++++++++++++++++-- .../defaults/cec-build-subst-ice.rs | 10 ++++++ .../defaults/cec-build-subst-ice.stderr | 12 +++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.rs create mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index c78151271c171..16ec935ba1ad0 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -85,7 +85,10 @@ impl<'tcx> Const<'tcx> { _ => expr, }; - use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; + use hir::{ + def::DefKind::ConstParam, def::Res, ExprKind, GenericParam, GenericParamKind, Node, + Path, QPath, + }; let val = match expr.kind { ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { // Find the name and index of the const parameter by indexing the generics of @@ -100,7 +103,33 @@ impl<'tcx> Const<'tcx> { } _ => ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), - substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + substs: { + let ct_hir_id = tcx.hir().local_def_id_to_hir_id(def.did); + let parent_id = tcx.hir().get_parent_node(ct_hir_id); + match tcx.hir().get(parent_id) { + // If this anon ct is a cg default we should only provide non-fwd declared params + // https://github.com/rust-lang/rust/issues/83938 + Node::GenericParam(GenericParam { + hir_id: param_id, + kind: GenericParamKind::Const { .. }, + .. + }) => { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id.to_def_id()); + let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); + let param_def_idx = generics.param_def_id_to_index[¶m_def]; + let substs = generics + .params + .iter() + .map(|param| tcx.mk_param_from_def(param)) + .take(param_def_idx as usize) + .collect::>(); + tcx.intern_substs(&substs) + } + _ => InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), + } + }, promoted: None, }), }; diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs b/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs new file mode 100644 index 0000000000000..d43e136d5748a --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs @@ -0,0 +1,10 @@ +#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)] +#![allow(incomplete_features)] + +pub struct Bar; +pub fn foo() -> Bar { + loop {} +} +//~^ error: unconstrained generic constant + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr new file mode 100644 index 0000000000000..0508007412c7d --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr @@ -0,0 +1,12 @@ +error: unconstrained generic constant + --> $DIR/cec-build-subst-ice.rs:5:34 + | +LL | pub struct Bar; + | --------- required by this bound in `Bar` +LL | pub fn foo() -> Bar { loop {} } + | ^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` + +error: aborting due to previous error + From b44be27999d26ee5f6712704e5d0535c2ea08e70 Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 10 Jul 2021 14:53:37 +0100 Subject: [PATCH 02/22] Moves changes to explicit_preds_of/inferred_outlives_of/generics_of --- compiler/rustc_middle/src/ty/consts.rs | 33 +------------- compiler/rustc_typeck/src/collect.rs | 44 ++++++++++++++++++- compiler/rustc_typeck/src/outlives/mod.rs | 16 +++++++ .../defaults/cec-build-subst-ice.stderr | 11 ++++- 4 files changed, 71 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 16ec935ba1ad0..c78151271c171 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -85,10 +85,7 @@ impl<'tcx> Const<'tcx> { _ => expr, }; - use hir::{ - def::DefKind::ConstParam, def::Res, ExprKind, GenericParam, GenericParamKind, Node, - Path, QPath, - }; + use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; let val = match expr.kind { ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { // Find the name and index of the const parameter by indexing the generics of @@ -103,33 +100,7 @@ impl<'tcx> Const<'tcx> { } _ => ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), - substs: { - let ct_hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - let parent_id = tcx.hir().get_parent_node(ct_hir_id); - match tcx.hir().get(parent_id) { - // If this anon ct is a cg default we should only provide non-fwd declared params - // https://github.com/rust-lang/rust/issues/83938 - Node::GenericParam(GenericParam { - hir_id: param_id, - kind: GenericParamKind::Const { .. }, - .. - }) => { - let item_id = tcx.hir().get_parent_node(*param_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id.to_def_id()); - let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); - let param_def_idx = generics.param_def_id_to_index[¶m_def]; - let substs = generics - .params - .iter() - .map(|param| tcx.mk_param_from_def(param)) - .take(param_def_idx as usize) - .collect::>(); - tcx.intern_substs(&substs) - } - _ => InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), - } - }, + substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), promoted: None, }), }; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 583ba9392f062..924a0b8410a12 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1441,6 +1441,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo` is not allowed. None } else if tcx.lazy_normalization() { + // Only provide backwards declared generics to cg defaults (#83938) + if let Node::GenericParam(GenericParam { + hir_id: param_id, + kind: GenericParamKind::Const { .. }, + .. + }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) + { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id.to_def_id()); + let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); + let param_def_idx = generics.param_def_id_to_index[¶m_def]; + let params = generics.params[..param_def_idx as usize].to_owned(); + let param_def_id_to_index = + params.iter().map(|param| (param.def_id, param.index)).collect(); + + return ty::Generics { + parent: generics.parent, + parent_count: generics.parent_count, + params, + param_def_id_to_index, + has_self: generics.has_self, + has_late_bound_regions: generics.has_late_bound_regions, + }; + } + // HACK(eddyb) this provides the correct generics when // `feature(const_generics)` is enabled, so that const expressions // used with const generics, e.g. `Foo<{N+1}>`, can work at all. @@ -2359,7 +2385,8 @@ fn trait_explicit_predicates_and_bounds( } fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - if let DefKind::Trait = tcx.def_kind(def_id) { + let def_kind = tcx.def_kind(def_id); + if let DefKind::Trait = def_kind { // Remove bounds on associated types from the predicates, they will be // returned by `explicit_item_bounds`. let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local()); @@ -2404,6 +2431,21 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } } else { + if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { + // Provide predicates of parent item of cg defaults manually + // as generics_of doesn't return a parent for the generics + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + if let Node::GenericParam(hir::GenericParam { + hir_id: param_id, + kind: hir::GenericParamKind::Const { .. }, + .. + }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) + { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + return tcx.explicit_predicates_of(item_def_id); + } + } gather_explicit_predicates_of(tcx, def_id) } } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index d7eb31c2abef5..c2f8525f7aba6 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -20,6 +20,22 @@ pub fn provide(providers: &mut Providers) { fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate<'_>, Span)] { let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()); + if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() + { + // Provide inferred outlive preds of parent item of cg defaults manually + // as generics_of doesn't return a parent for the generics + if let Node::GenericParam(hir::GenericParam { + hir_id: param_id, + kind: hir::GenericParamKind::Const { .. }, + .. + }) = tcx.hir().get(tcx.hir().get_parent_node(id)) + { + let item_id = tcx.hir().get_parent_node(*param_id); + let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + return tcx.inferred_outlives_of(item_def_id); + } + } + match tcx.hir().get(id) { Node::Item(item) => match item.kind { hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => { diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr index 0508007412c7d..30a01d48c4c8d 100644 --- a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr +++ b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr @@ -8,5 +8,14 @@ LL | pub fn foo() -> Bar { loop {} } | = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` -error: aborting due to previous error +error: unconstrained generic constant + --> $DIR/cec-build-subst-ice.rs:15:8 + | +LL | type Alias = [T; NP]; + | ---------- required by this bound in `Alias::{constant#0}` +LL | fn alias(_: [T; N], _: T) +LL | -> Alias + | ^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); {N+1usize}]:` From e276b860e25a900037dd964b5c4b42afe1187abc Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 10 Jul 2021 17:38:39 +0100 Subject: [PATCH 03/22] redo tests --- .../defaults/cec-build-subst-ice.rs | 10 -------- .../defaults/cec-build-subst-ice.stderr | 21 ---------------- .../defaults/cec-concrete-default.rs | 14 +++++++++++ .../defaults/cec-concrete-default.stderr | 12 ++++++++++ .../cec-generic-default-mismatched-types.rs | 16 +++++++++++++ ...ec-generic-default-mismatched-types.stderr | 12 ++++++++++ .../defaults/cec-generic-default.rs | 24 +++++++++++++++++++ .../defaults/cec-generic-default.stderr | 18 ++++++++++++++ 8 files changed, 96 insertions(+), 31 deletions(-) delete mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.rs delete mode 100644 src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr create mode 100644 src/test/ui/const-generics/defaults/cec-concrete-default.rs create mode 100644 src/test/ui/const-generics/defaults/cec-concrete-default.stderr create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default.rs create mode 100644 src/test/ui/const-generics/defaults/cec-generic-default.stderr diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs b/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs deleted file mode 100644 index d43e136d5748a..0000000000000 --- a/src/test/ui/const-generics/defaults/cec-build-subst-ice.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)] -#![allow(incomplete_features)] - -pub struct Bar; -pub fn foo() -> Bar { - loop {} -} -//~^ error: unconstrained generic constant - -fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr b/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr deleted file mode 100644 index 30a01d48c4c8d..0000000000000 --- a/src/test/ui/const-generics/defaults/cec-build-subst-ice.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: unconstrained generic constant - --> $DIR/cec-build-subst-ice.rs:5:34 - | -LL | pub struct Bar; - | --------- required by this bound in `Bar` -LL | pub fn foo() -> Bar { loop {} } - | ^^^^^^^ - | - = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` - -error: unconstrained generic constant - --> $DIR/cec-build-subst-ice.rs:15:8 - | -LL | type Alias = [T; NP]; - | ---------- required by this bound in `Alias::{constant#0}` -LL | fn alias(_: [T; N], _: T) -LL | -> Alias - | ^^^^^^^^^^^ - | - = help: try adding a `where` bound using this expression: `where [(); {N+1usize}]:` - diff --git a/src/test/ui/const-generics/defaults/cec-concrete-default.rs b/src/test/ui/const-generics/defaults/cec-concrete-default.rs new file mode 100644 index 0000000000000..c2a41cf2ad7dd --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-concrete-default.rs @@ -0,0 +1,14 @@ +#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)] +#![allow(incomplete_features)] + +struct Foo; +fn no_constraining() -> Foo<10> { + Foo::<10, 11> +} + +pub fn different_than_default() -> Foo<10> { + Foo::<10, 12> + //~^ error: mismatched types +} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-concrete-default.stderr b/src/test/ui/const-generics/defaults/cec-concrete-default.stderr new file mode 100644 index 0000000000000..090e507b7f34e --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-concrete-default.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/cec-concrete-default.rs:10:5 + | +LL | Foo::<10, 12> + | ^^^^^^^^^^^^^ expected `11_usize`, found `12_usize` + | + = note: expected type `11_usize` + found type `12_usize` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs new file mode 100644 index 0000000000000..15822dfac1c5a --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.rs @@ -0,0 +1,16 @@ +#![feature(const_generics, const_evaluatable_checked, const_generics_defaults)] +#![allow(incomplete_features)] + +struct Foo; +fn should_unify() -> Foo where [(); { N + 1 }]: { + Foo:: +} +pub fn shouldnt_unify() -> Foo +where + [(); { N + 1 }]:, + [(); { N + 2 }]:, { + Foo:: + //~^ error: mismatched types +} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr new file mode 100644 index 0000000000000..f97fc26a07321 --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default-mismatched-types.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/cec-generic-default-mismatched-types.rs:12:5 + | +LL | Foo:: + | ^^^^^^^^^^^^^^^^^^^ expected `{ N + 1 }`, found `{ N + 2 }` + | + = note: expected type `{ N + 1 }` + found type `{ N + 2 }` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/defaults/cec-generic-default.rs b/src/test/ui/const-generics/defaults/cec-generic-default.rs new file mode 100644 index 0000000000000..76ff7c7801b06 --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default.rs @@ -0,0 +1,24 @@ +#![feature(const_evaluatable_checked, const_generics, const_generics_defaults)] +#![allow(incomplete_features)] + +pub struct Foo; +pub fn needs_evaluatable_bound() -> Foo { + //~^ error: unconstrained generic constant + loop {} +} +pub fn has_evaluatable_bound() -> Foo where [(); N1 + 1]: { + loop {} +} + +type FooAlias = [(); NP]; +fn needs_evaluatable_bound_alias() -> FooAlias +{ + //~^^ error: unconstrained generic constant + todo!() +} +fn has_evaluatable_bound_alias() -> FooAlias +where [(); N + 1]: { + todo!() +} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/cec-generic-default.stderr b/src/test/ui/const-generics/defaults/cec-generic-default.stderr new file mode 100644 index 0000000000000..0234ea8b9a4a9 --- /dev/null +++ b/src/test/ui/const-generics/defaults/cec-generic-default.stderr @@ -0,0 +1,18 @@ +error: unconstrained generic constant + --> $DIR/cec-generic-default.rs:5:54 + | +LL | pub fn needs_evaluatable_bound() -> Foo { + | ^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` + +error: unconstrained generic constant + --> $DIR/cec-generic-default.rs:14:58 + | +LL | fn needs_evaluatable_bound_alias() -> FooAlias + | ^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N + 1 }]:` + +error: aborting due to 2 previous errors + From 8c40360ed413c0024787cf14fc83af0d98037c7a Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 13 Jul 2021 17:23:26 +0100 Subject: [PATCH 04/22] Put checking if anonct is a default into a method on hir map --- compiler/rustc_hir/src/hir.rs | 3 +++ compiler/rustc_middle/src/hir/map/mod.rs | 13 +++++++++++ compiler/rustc_typeck/src/collect.rs | 28 +++++++---------------- compiler/rustc_typeck/src/outlives/mod.rs | 13 ++++------- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a7ce92ea57917..04c29c50e75a1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1422,6 +1422,9 @@ pub type Lit = Spanned; /// These are usually found nested inside types (e.g., array lengths) /// or expressions (e.g., repeat counts), and also used to define /// explicit discriminant values for enum variants. +/// +/// You can check if this anon const is a default in a const param +/// `const N: usize = { ... }` with [Map::opt_const_param_default_param_hir_id] #[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] pub struct AnonConst { pub hir_id: HirId, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 07b39c97c492a..9d81407c330c4 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -901,6 +901,19 @@ impl<'hir> Map<'hir> { pub fn node_to_string(&self, id: HirId) -> String { hir_id_to_string(self, id) } + + /// Returns the HirId of `N` in `struct Foo` when + /// called with the HirId for the `{ ... }` anon const + pub fn opt_const_param_default_param_hir_id(&self, anon_const: HirId) -> Option { + match self.get(self.get_parent_node(anon_const)) { + Node::GenericParam(GenericParam { + hir_id: param_id, + kind: GenericParamKind::Const { .. }, + .. + }) => Some(*param_id), + _ => None, + } + } } impl<'hir> intravisit::Map<'hir> for Map<'hir> { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 924a0b8410a12..31cafb9d96652 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1441,17 +1441,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo` is not allowed. None } else if tcx.lazy_normalization() { - // Only provide backwards declared generics to cg defaults (#83938) - if let Node::GenericParam(GenericParam { - hir_id: param_id, - kind: GenericParamKind::Const { .. }, - .. - }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) - { - let item_id = tcx.hir().get_parent_node(*param_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id.to_def_id()); - let param_def = tcx.hir().local_def_id(*param_id).to_def_id(); + // Only provide backwards declared generics to cg defaults (#86580) + if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + let generics = tcx.generics_of(parent_def_id.to_def_id()); + let param_def = tcx.hir().local_def_id(param_id).to_def_id(); let param_def_idx = generics.param_def_id_to_index[¶m_def]; let params = generics.params[..param_def_idx as usize].to_owned(); let param_def_id_to_index = @@ -2432,16 +2425,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide predicates of parent item of cg defaults manually - // as generics_of doesn't return a parent for the generics + // Provide predicates of parent item of cg defaults manually as `generics_of` + // doesn't set the parent item as the parent for the generics (#86580) let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if let Node::GenericParam(hir::GenericParam { - hir_id: param_id, - kind: hir::GenericParamKind::Const { .. }, - .. - }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) - { - let item_id = tcx.hir().get_parent_node(*param_id); + if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + let item_id = tcx.hir().get_parent_item(hir_id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); return tcx.explicit_predicates_of(item_def_id); } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index c2f8525f7aba6..16d698fc8cb0f 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -22,15 +22,10 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide inferred outlive preds of parent item of cg defaults manually - // as generics_of doesn't return a parent for the generics - if let Node::GenericParam(hir::GenericParam { - hir_id: param_id, - kind: hir::GenericParamKind::Const { .. }, - .. - }) = tcx.hir().get(tcx.hir().get_parent_node(id)) - { - let item_id = tcx.hir().get_parent_node(*param_id); + // Provide predicates of parent item of cg defaults manually as `generics_of` + // doesn't set the parent item as the parent for the generics (#86580) + if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) { + let item_id = tcx.hir().get_parent_item(id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); return tcx.inferred_outlives_of(item_def_id); } From 8462a378f313f7f279fb8f98a7dad703ef9ef897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 17 Jul 2021 01:20:10 +0200 Subject: [PATCH 05/22] avoid temporary vectors Avoid collecting an interator just to re-iterate immediately. Rather reuse the previous iterator. (clippy::needless_collect) --- .../rustc_builtin_macros/src/deriving/generic/ty.rs | 10 +++------- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 6b7d0e1f204b5..00d75be439964 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -72,13 +72,9 @@ impl Path { ) -> ast::Path { let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); let lt = mk_lifetimes(cx, span, &self.lifetime); - let tys: Vec> = - self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - let params = lt - .into_iter() - .map(GenericArg::Lifetime) - .chain(tys.into_iter().map(GenericArg::Type)) - .collect(); + let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)); + let params = + lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect(); match self.kind { PathKind::Global => cx.path_all(span, true, idents, params), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e3a79fe265330..a5a804a291643 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2134,7 +2134,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let new_lt = generics .as_ref() .and_then(|(parent_g, g)| { - let possible: Vec<_> = (b'a'..=b'z').map(|c| format!("'{}", c as char)).collect(); + let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char)); let mut lts_names = g .params .iter() @@ -2150,7 +2150,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } let lts = lts_names.iter().map(|s| -> &str { &*s }).collect::>(); - possible.into_iter().find(|candidate| !lts.contains(&candidate.as_str())) + possible.find(|candidate| !lts.contains(&candidate.as_str())) }) .unwrap_or("'lt".to_string()); let add_lt_sugg = generics From abfd44d8a3b13d56dc0c7904c35a8155a62f19fb Mon Sep 17 00:00:00 2001 From: Ellen Date: Sat, 17 Jul 2021 11:59:42 +0100 Subject: [PATCH 06/22] Comments --- compiler/rustc_typeck/src/collect.rs | 43 +++++++++++++++++++++-- compiler/rustc_typeck/src/outlives/mod.rs | 14 ++++++-- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 31cafb9d96652..a2ac3e2555f50 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1441,16 +1441,43 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // of a const parameter type, e.g. `struct Foo` is not allowed. None } else if tcx.lazy_normalization() { - // Only provide backwards declared generics to cg defaults (#86580) if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + // If the def_id we are calling generics_of on is an anon ct default i.e: + // + // struct Foo; + // ^^^ ^ ^^^^^^ def id of this anon const + // ^ ^ param_id + // ^ parent_def_id + // + // then we only want to return generics for params to the left of `N`. If we don't do that we + // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`. + // + // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as + // we substitute the defaults with the partially built substs when we build the substs. Subst'ing + // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building. + // + // We fix this by having this function return the parent's generics ourselves and truncating the + // generics to only include non-forward declared params (with the exception of the `Self` ty) + // + // For the above code example that means we want `substs: []` + // For the following struct def we want `substs: [N#0]` when generics_of is called on + // the def id of the `{ N + 1 }` anon const + // struct Foo; + // + // This has some implications for how we get the predicates available to the anon const + // see `explicit_predicates_of` for more information on this let generics = tcx.generics_of(parent_def_id.to_def_id()); let param_def = tcx.hir().local_def_id(param_id).to_def_id(); let param_def_idx = generics.param_def_id_to_index[¶m_def]; + // In the above example this would be .params[..N#0] let params = generics.params[..param_def_idx as usize].to_owned(); let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); return ty::Generics { + // we set the parent of these generics to be our parent's parent so that we + // dont end up with substs: [N, M, N] for the const default on a struct like this: + // struct Foo; parent: generics.parent, parent_count: generics.parent_count, params, @@ -2425,12 +2452,22 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide predicates of parent item of cg defaults manually as `generics_of` - // doesn't set the parent item as the parent for the generics (#86580) let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + // In `generics_of` we set the generics' parent to be our parent's parent which means that + // we lose out on the predicates of our actual parent if we dont return those predicates here. + // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) + // + // struct Foo::ASSOC }>(T) where T: Trait; + // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling + // ^^^ explicit_predicates_of on + // parent item we dont have set as the + // parent of generics returned by `generics_of` + // + // In the above code we want the anon const to have predicates in its param env for `T: Trait` let item_id = tcx.hir().get_parent_item(hir_id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + // In the above code example we would be calling `explicit_predicates_of(Foo)` here return tcx.explicit_predicates_of(item_def_id); } } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 16d698fc8cb0f..70a2ba7fcd9d9 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -22,11 +22,21 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { - // Provide predicates of parent item of cg defaults manually as `generics_of` - // doesn't set the parent item as the parent for the generics (#86580) if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) { + // In `generics_of` we set the generics' parent to be our parent's parent which means that + // we lose out on the predicates of our actual parent if we dont return those predicates here. + // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) + // + // struct Foo<'a, 'b, const N: usize = { ... }>(&'a &'b ()); + // ^^^ ^^^^^^^ the def id we are calling + // ^^^ inferred_outlives_of on + // parent item we dont have set as the + // parent of generics returned by `generics_of` + // + // In the above code we want the anon const to have predicates in its param env for `'b: 'a` let item_id = tcx.hir().get_parent_item(id); let item_def_id = tcx.hir().local_def_id(item_id).to_def_id(); + // In the above code example we would be calling `inferred_outlives_of(Foo)` here return tcx.inferred_outlives_of(item_def_id); } } From d05a286449809cba5043bdac39074198a63cda6d Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 19 Jul 2021 18:50:06 +0800 Subject: [PATCH 07/22] Iterate through impls only when permitted --- .../src/transform/check_consts/validation.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 646ae8ced7eb4..cfc538ef500a1 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -897,16 +897,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { permitted = true; } } - let mut const_impls = true; - tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| { - if const_impls { - if let hir::Constness::NotConst = tcx.impl_constness(imp) { - const_impls = false; + if !permitted { + // if trait's impls are all const, permit the call. + let mut const_impls = true; + tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| { + if const_impls { + if let hir::Constness::NotConst = tcx.impl_constness(imp) { + const_impls = false; + } } + }); + if const_impls { + permitted = true; } - }); - if const_impls { - permitted = true; } } From 4b82bbeac009c09c55e4a5458ee7338bddb14a44 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 19 Jul 2021 18:50:47 +0800 Subject: [PATCH 08/22] Recognize bounds on impls as const bounds --- compiler/rustc_hir/src/hir.rs | 21 +++++++++++++++++++ .../rustc_typeck/src/check/fn_ctxt/mod.rs | 9 +------- compiler/rustc_typeck/src/collect.rs | 7 +------ .../call-generic-in-impl.rs | 15 +++++++++++++ 4 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4b2679e164aac..213887e26179c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3064,6 +3064,27 @@ impl<'hir> Node<'hir> { Node::Crate(_) | Node::Visibility(_) => None, } } + + /// Returns `Constness::Const` when this node is a const fn/impl. + pub fn constness(&self) -> Constness { + match self { + Node::Item(Item { + kind: ItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..), + .. + }) + | Node::TraitItem(TraitItem { + kind: TraitItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..), + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..), + .. + }) + | Node::Item(Item { kind: ItemKind::Impl(Impl { constness, .. }), .. }) => *constness, + + _ => Constness::NotConst, + } + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 4da4835f7cfbb..13686cfec809a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -15,7 +15,6 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; @@ -175,13 +174,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn default_constness_for_trait_bounds(&self) -> hir::Constness { - // FIXME: refactor this into a method - let node = self.tcx.hir().get(self.body_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() - } else { - hir::Constness::NotConst - } + self.tcx.hir().get(self.body_id).constness() } fn get_type_parameter_bounds( diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 506ca98b96026..1a4c2eb515584 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -35,7 +35,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::weak_lang_items; use rustc_hir::{GenericParamKind, HirId, Node}; -use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; @@ -358,11 +357,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } fn default_constness_for_trait_bounds(&self) -> hir::Constness { - if let Some(fn_like) = FnLikeNode::from_node(self.node()) { - fn_like.constness() - } else { - hir::Constness::NotConst - } + self.node().constness() } fn get_type_parameter_bounds( diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs new file mode 100644 index 0000000000000..536c1d7374023 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs @@ -0,0 +1,15 @@ +// check-pass +#![feature(const_fn_trait_bound)] +#![feature(const_trait_impl)] + +trait MyPartialEq { + fn eq(&self, other: &Self) -> bool; +} + +impl const MyPartialEq for T { + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(self, other) + } +} + +fn main() {} From 7066398ec5cd67b1e0359d271022694cda23961a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jul 2021 11:50:14 +0200 Subject: [PATCH 09/22] Don't render in items' summary --- src/librustdoc/html/markdown.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e21469dc9c343..908e292d968ef 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -57,7 +57,7 @@ pub(crate) fn opts() -> Options { /// A subset of [`opts()`] used for rendering summaries. pub(crate) fn summary_opts() -> Options { - Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION + Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION | Options::ENABLE_TABLES } /// When `to_string` is called, this struct will emit the HTML corresponding to @@ -522,6 +522,10 @@ fn check_if_allowed_tag(t: &Tag<'_>) -> bool { ) } +fn is_forbidden_tag(t: &Tag<'_>) -> bool { + matches!(t, Tag::CodeBlock(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell) +} + impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { type Item = Event<'a>; @@ -535,14 +539,17 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { if let Some(event) = self.inner.next() { let mut is_start = true; let is_allowed_tag = match event { - Event::Start(Tag::CodeBlock(_)) | Event::End(Tag::CodeBlock(_)) => { - return None; - } Event::Start(ref c) => { + if is_forbidden_tag(c) { + return None; + } self.depth += 1; check_if_allowed_tag(c) } Event::End(ref c) => { + if is_forbidden_tag(c) { + return None; + } self.depth -= 1; is_start = false; check_if_allowed_tag(c) From d6dc840cf7b29ea2be93a4c443b38234f34d9902 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 Jul 2021 12:02:41 +0200 Subject: [PATCH 10/22] Add test to ensure tables are not inside items summary --- src/test/rustdoc-gui/item-summary-table.goml | 6 ++++++ src/test/rustdoc-gui/src/lib2/lib.rs | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 src/test/rustdoc-gui/item-summary-table.goml diff --git a/src/test/rustdoc-gui/item-summary-table.goml b/src/test/rustdoc-gui/item-summary-table.goml new file mode 100644 index 0000000000000..6bf4e288c4377 --- /dev/null +++ b/src/test/rustdoc-gui/item-summary-table.goml @@ -0,0 +1,6 @@ +// This test ensures that
elements aren't display in items summary. +goto: file://|DOC_PATH|/lib2/summary_table/index.html +// We check that we picked the right item first. +assert-text: (".item-table .item-left", "Foo") +// Then we check that its summary is empty. +assert-text: (".item-table .item-right", "") diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 0466909479b67..84091ad968f20 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -54,3 +54,10 @@ pub mod long_trait { pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem: DerefMut + From + Send + Sync + AsRef + 'static {} } + +pub mod summary_table { + /// | header 1 | header 2 | + /// | -------- | -------- | + /// | content | content | + pub struct Foo; +} From 76ab8a6b107060aa09ec5dc0901d29502bda8497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 19 Jul 2021 17:07:21 +0300 Subject: [PATCH 11/22] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index fe00358888a24..ea105f9396a9d 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit fe00358888a24c64878abc15f09b0e60e16db9d6 +Subproject commit ea105f9396a9dab68e71efb06016b7c76c83ba7c From 2a56a681c4cfd56822e447a66adccdc32580b46a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 19 Jul 2021 07:06:42 -0700 Subject: [PATCH 12/22] Add comments explaining the unix command-line argument support. Following up on #87236, add comments to the unix command-line argument support explaining that the code doesn't mutate the system-provided argc/argv, and that this is why the code doesn't need a lock or special memory ordering. --- library/std/src/sys/unix/args.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index ad93fa610c481..0bd1ea645779f 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -77,10 +77,18 @@ mod imp { use crate::ptr; use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering}; + // The system-provided argc and argv, which we store in static memory + // here so that we can defer the work of parsing them until its actually + // needed. + // + // Note that we never mutate argv/argc, the argv array, or the argv + // strings, which allows the code in this file to be very simple. static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); unsafe fn really_init(argc: isize, argv: *const *const u8) { + // These don't need to be ordered with each other or other stores, + // because they only hold the unmodified system-provide argv/argc. ARGC.store(argc, Ordering::Relaxed); ARGV.store(argv as *mut _, Ordering::Relaxed); } @@ -122,8 +130,14 @@ mod imp { fn clone() -> Vec { unsafe { - // Load ARGC and ARGV without a lock. If the store to either ARGV or - // ARGC isn't visible yet, we'll return an empty argument list. + // Load ARGC and ARGV, which hold the unmodified system-provided + // argc/argv, so we can read the pointed-to memory without atomics + // or synchronization. + // + // If either ARGC or ARGV is still zero or null, then either there + // really are no arguments, or someone is asking for `args()` + // before initialization has completed, and we return an empty + // list. let argv = ARGV.load(Ordering::Relaxed); let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) }; (0..argc) From 64f4e34d69a99b00e635a572a0643dd008bb5a3a Mon Sep 17 00:00:00 2001 From: Chinmay Deshpande Date: Mon, 19 Jul 2021 20:03:03 -0700 Subject: [PATCH 13/22] Fix typo in compile.rs --- src/bootstrap/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1fae4bee732c0..5b9ea97dea59d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -2,7 +2,7 @@ //! library. //! //! This module contains some of the real meat in the rustbuild build system -//! which is where Cargo is used to compiler the standard library, libtest, and +//! which is where Cargo is used to compile the standard library, libtest, and //! compiler. This module is also responsible for assembling the sysroot as it //! goes along from the output of the previous stage. From b9b0a5e05400d61df0f0f8745a9d9e7bf8a85e3e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jul 2021 16:38:14 +0000 Subject: [PATCH 14/22] Fix VecMap::iter_mut It used to allow you to mutate the key, even though that can invalidate the map by creating duplicate keys. --- compiler/rustc_data_structures/src/lib.rs | 1 + compiler/rustc_data_structures/src/vec_map.rs | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 16151e9dca5e0..4467980054f54 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -24,6 +24,7 @@ #![feature(new_uninit)] #![feature(once_cell)] #![feature(maybe_uninit_uninit_array)] +#![feature(min_type_alias_impl_trait)] #![allow(rustc::default_hash_types)] #![deny(unaligned_references)] diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs index 1786fa340cc8b..96e33184658a3 100644 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ b/compiler/rustc_data_structures/src/vec_map.rs @@ -1,6 +1,6 @@ use std::borrow::Borrow; use std::iter::FromIterator; -use std::slice::{Iter, IterMut}; +use std::slice::Iter; use std::vec::IntoIter; use crate::stable_hasher::{HashStable, StableHasher}; @@ -67,7 +67,7 @@ where self.into_iter() } - pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> { + pub fn iter_mut(&mut self) -> impl Iterator { self.into_iter() } } @@ -108,12 +108,12 @@ impl<'a, K, V> IntoIterator for &'a VecMap { } impl<'a, K, V> IntoIterator for &'a mut VecMap { - type Item = &'a mut (K, V); - type IntoIter = IterMut<'a, (K, V)>; + type Item = (&'a K, &'a mut V); + type IntoIter = impl Iterator; #[inline] fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() + self.0.iter_mut().map(|(k, v)| (&*k, v)) } } From 75d9ed7b024aefa9e48b17f7f49b351b056b83ed Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 19 Jul 2021 16:50:43 +0000 Subject: [PATCH 15/22] Make mir borrowck's use of opaque types independent of the typeck query's result --- compiler/rustc_data_structures/src/vec_map.rs | 4 + .../src/borrow_check/type_check/mod.rs | 149 ++++++++---------- .../assoc-type-eq-with-dyn-atb-fail.rs | 1 - .../assoc-type-eq-with-dyn-atb-fail.stderr | 8 +- src/test/ui/impl-trait/auto-trait-leak.rs | 1 - src/test/ui/impl-trait/auto-trait-leak.stderr | 34 ++-- ...does_not_live_long_enough.full_tait.stderr | 11 +- ..._does_not_live_long_enough.min_tait.stderr | 11 +- .../generic_type_does_not_live_long_enough.rs | 1 - .../issue-57611-trait-alias.full_tait.stderr | 49 +----- .../issue-57611-trait-alias.min_tait.stderr | 49 +----- .../issue-57611-trait-alias.rs | 4 - .../ui/type-alias-impl-trait/issue-60371.rs | 1 - .../type-alias-impl-trait/issue-60371.stderr | 13 +- .../ui/type-alias-impl-trait/issue-74761-2.rs | 19 +++ .../issue-74761-2.stderr | 34 ++++ .../multiple-def-uses-in-one-fn2.rs | 2 +- .../multiple-def-uses-in-one-fn2.stderr | 14 +- .../multiple-def-uses-in-one-fn3.rs | 1 + .../multiple-def-uses-in-one-fn3.stderr | 17 +- 20 files changed, 162 insertions(+), 261 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/issue-74761-2.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-74761-2.stderr diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs index 96e33184658a3..e3fa587985df0 100644 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ b/compiler/rustc_data_structures/src/vec_map.rs @@ -70,6 +70,10 @@ where pub fn iter_mut(&mut self) -> impl Iterator { self.into_iter() } + + pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) { + self.0.retain(f) + } } impl Default for VecMap { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index aa3ff98f7ff9f..de327047a872a 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -26,7 +26,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, @@ -60,7 +60,6 @@ use crate::borrow_check::{ LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, }, region_infer::{ClosureRegionRequirementsExt, TypeTest}, - renumber, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, Upvar, @@ -180,7 +179,66 @@ pub(crate) fn type_check<'mir, 'tcx>( liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); translate_outlives_facts(&mut cx); - cx.opaque_type_values + let mut opaque_type_values = cx.opaque_type_values; + + for (_, revealed_ty) in &mut opaque_type_values { + // FIXME(oli-obk): Instead of looping, implement a visitor like + // FullTypeResolver. We can't use FullTypeResolver here, as that will + // resolve lifetimes lexically, which it can't because we didn't do old + // borrowck stuff. We want to use MIR borrowck information instead. + + while revealed_ty.has_infer_types_or_consts() { + let prev = *revealed_ty; + trace!(prev=?prev.kind()); + let type_resolved = infcx.shallow_resolve(prev); + trace!(type_resolved=?type_resolved.kind()); + if prev == type_resolved { + infcx.tcx.sess.delay_span_bug( + body.span, + &format!("could not resolve {:#?}", type_resolved.kind()), + ); + *revealed_ty = infcx.tcx.ty_error(); + break; + } + *revealed_ty = type_resolved; + } + } + + opaque_type_values.retain(|(opaque_type_key, resolved_ty)| { + let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { + *def_id == opaque_type_key.def_id + } else { + false + }; + + if concrete_is_opaque { + // We're using an opaque `impl Trait` type without + // 'revealing' it. For example, code like this: + // + // type Foo = impl Debug; + // fn foo1() -> Foo { ... } + // fn foo2() -> Foo { foo1() } + // + // In `foo2`, we're not revealing the type of `Foo` - we're + // just treating it as the opaque type. + // + // When this occurs, we do *not* want to try to equate + // the concrete type with the underlying defining type + // of the opaque type - this will always fail, since + // the defining type of an opaque type is always + // some other type (e.g. not itself) + // Essentially, none of the normal obligations apply here - + // we're just passing around some unknown opaque type, + // without actually looking at the underlying type it + // gets 'revealed' into + debug!( + "eq_opaque_type_and_type: non-defining use of {:?}", + opaque_type_key.def_id, + ); + } + !concrete_is_opaque + }); + opaque_type_values }, ); @@ -1240,13 +1298,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } let infcx = self.infcx; - let tcx = infcx.tcx; let param_env = self.param_env; let body = self.body; let mir_def_id = body.source.def_id().expect_local(); - // the "concrete opaque types" maps - let concrete_opaque_types = &tcx.typeck(mir_def_id).concrete_opaque_types; let mut opaque_type_values = VecMap::new(); debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id); @@ -1296,88 +1351,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .eq(output_ty, revealed_ty)?, ); - // For each opaque type `Foo` inferred by this value, we want to equate - // the inference variable `?T` with the revealed type that was computed - // earlier by type check. for &(opaque_type_key, opaque_decl) in &opaque_type_map { - let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty); - let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { - *def_id == opaque_type_key.def_id - } else { - false - }; - - // The revealed type computed by the earlier phase of type check. - // In our example, this would be `(U, u32)`. Note that this references - // the type parameter `U` from the definition of `Foo`. - let concrete_ty = match concrete_opaque_types - .get_by(|(key, _)| key.def_id == opaque_type_key.def_id) - { - None => { - if !concrete_is_opaque { - tcx.sess.delay_span_bug( - body.span, - &format!( - "Non-defining use of {:?} with revealed type", - opaque_type_key.def_id, - ), - ); - } - continue; - } - Some(concrete_ty) => concrete_ty, - }; - debug!("concrete_ty = {:?}", concrete_ty); - - // Apply the substitution, in this case `[U -> T]`, so that the - // concrete type becomes `Foo<(T, u32)>` - let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs); - - // "Renumber" this, meaning that we replace all the regions - // with fresh inference variables. Not relevant to our example. - let renumbered_opaque_defn_ty = - renumber::renumber_regions(infcx, subst_opaque_defn_ty); - - debug!( - "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", - concrete_ty, resolved_ty, renumbered_opaque_defn_ty, - ); - - if !concrete_is_opaque { - // Equate the instantiated opaque type `opaque_decl.concrete_ty` (`?T`, - // in our example) with the renumbered version that we took from - // the type check results (`Foo<(T, u32)>`). - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?, - ); - opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty); - } else { - // We're using an opaque `impl Trait` type without - // 'revealing' it. For example, code like this: - // - // type Foo = impl Debug; - // fn foo1() -> Foo { ... } - // fn foo2() -> Foo { foo1() } - // - // In `foo2`, we're not revealing the type of `Foo` - we're - // just treating it as the opaque type. - // - // When this occurs, we do *not* want to try to equate - // the concrete type with the underlying defining type - // of the opaque type - this will always fail, since - // the defining type of an opaque type is always - // some other type (e.g. not itself) - // Essentially, none of the normal obligations apply here - - // we're just passing around some unknown opaque type, - // without actually looking at the underlying type it - // gets 'revealed' into - debug!( - "eq_opaque_type_and_type: non-defining use of {:?}", - opaque_type_key.def_id, - ); - } + opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty); } debug!("eq_opaque_type_and_type: equated"); diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs index 73b23da5bcb66..7950dd3e99e29 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs @@ -29,7 +29,6 @@ impl Bar for AssocNoCopy { impl Thing for AssocNoCopy { type Out = Box>; //~^ ERROR the trait bound `String: Copy` is not satisfied - //~| ERROR the trait bound `String: Copy` is not satisfied fn func() -> Self::Out { Box::new(AssocNoCopy) diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr index 414d74d4786d9..0f1d35be0eb7a 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr @@ -4,12 +4,6 @@ error[E0277]: the trait bound `String: Copy` is not satisfied LL | type Out = Box>; | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String` -error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28 - | -LL | type Out = Box>; - | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String` - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index 087f4582b21c3..c2fbbf94fd666 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -12,7 +12,6 @@ fn main() { fn cycle1() -> impl Clone { //~^ ERROR cycle detected send(cycle2().clone()); - //~^ ERROR cannot be sent between threads safely Rc::new(Cell::new(5)) } diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index e578c4b4f819e..3eb141cc2bb55 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -36,37 +36,37 @@ LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:20:16 + --> $DIR/auto-trait-leak.rs:19:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,22 +84,6 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0277]: `Rc` cannot be sent between threads safely - --> $DIR/auto-trait-leak.rs:14:5 - | -LL | fn send(_: T) {} - | ---- required by this bound in `send` -... -LL | send(cycle2().clone()); - | ^^^^ `Rc` cannot be sent between threads safely -... -LL | fn cycle2() -> impl Clone { - | ---------- within this `impl Clone` - | - = help: within `impl Clone`, the trait `Send` is not implemented for `Rc` - = note: required because it appears within the type `impl Clone` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0277, E0391. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr index 6394a1f8e8509..90a753b5a6de1 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.full_tait.stderr @@ -36,16 +36,7 @@ LL | type WrongGeneric = impl 'static; LL | fn wrong_generic(t: T) -> WrongGeneric { | - help: consider adding an explicit lifetime bound...: `T: 'static` -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:12:24 - | -LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `T` will meet its required lifetime bounds - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr index 49ead8b094c19..e50282201074e 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.min_tait.stderr @@ -27,16 +27,7 @@ LL | type WrongGeneric = impl 'static; LL | fn wrong_generic(t: T) -> WrongGeneric { | - help: consider adding an explicit lifetime bound...: `T: 'static` -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:12:24 - | -LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `T` will meet its required lifetime bounds - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs index 3dda34ff668ce..9f647d9e737fe 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs @@ -11,7 +11,6 @@ fn main() { type WrongGeneric = impl 'static; //~^ ERROR the parameter type `T` may not live long enough -//~| ERROR the parameter type `T` may not live long enough //~| ERROR: at least one trait must be specified fn wrong_generic(t: T) -> WrongGeneric { diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr index d90f328708a7b..61e8da91bbaa9 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.full_tait.stderr @@ -16,52 +16,5 @@ LL | type Bar = impl Baz; = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr index d019f40757eed..f65e91e52c713 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.min_tait.stderr @@ -7,52 +7,5 @@ LL | type Bar = impl Baz; = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&' X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:28:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:20:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error: aborting due to 5 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index ccc727e0bf01b..508ecdd88a482 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -19,10 +19,6 @@ struct X; impl Foo for X { type Bar = impl Baz; //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough - //~| ERROR mismatched types - //~| ERROR mismatched types fn bar(&self) -> Self::Bar { |x| x diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs index b7c8a58a65629..cee5e5a01cc2a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs @@ -9,7 +9,6 @@ trait Bug { impl Bug for &() { type Item = impl Bug; //~ ERROR `impl Trait` in type aliases is unstable //~^ ERROR the trait bound `(): Bug` is not satisfied - //~^^ ERROR the trait bound `(): Bug` is not satisfied const FUN: fn() -> Self::Item = || (); //~^ ERROR type alias impl trait is not permitted here diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index 4906ea9c2e261..a9df74689df29 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -8,7 +8,7 @@ LL | type Item = impl Bug; = help: add `#![feature(min_type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: type alias impl trait is not permitted here - --> $DIR/issue-60371.rs:14:40 + --> $DIR/issue-60371.rs:13:40 | LL | const FUN: fn() -> Self::Item = || (); | ^ @@ -25,16 +25,7 @@ LL | type Item = impl Bug; = help: the following implementations were found: <&() as Bug> -error[E0277]: the trait bound `(): Bug` is not satisfied - --> $DIR/issue-60371.rs:10:17 - | -LL | type Item = impl Bug; - | ^^^^^^^^ the trait `Bug` is not implemented for `()` - | - = help: the following implementations were found: - <&() as Bug> - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-74761-2.rs b/src/test/ui/type-alias-impl-trait/issue-74761-2.rs new file mode 100644 index 0000000000000..4b0f2afee5484 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761-2.rs @@ -0,0 +1,19 @@ +#![feature(member_constraints)] +#![feature(type_alias_impl_trait)] +//~^ WARN incomplete + +pub trait A { + type B; + fn f(&self) -> Self::B; +} +impl<'a, 'b> A for () { + //~^ ERROR the lifetime parameter `'a` is not constrained + //~| ERROR the lifetime parameter `'b` is not constrained + type B = impl core::fmt::Debug; + //~^ ERROR is unstable + + + fn f(&self) -> Self::B {} +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr b/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr new file mode 100644 index 0000000000000..4506a6e23d5c0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761-2.stderr @@ -0,0 +1,34 @@ +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/issue-74761-2.rs:12:14 + | +LL | type B = impl core::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #63063 for more information + = help: add `#![feature(min_type_alias_impl_trait)]` to the crate attributes to enable + +warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-74761-2.rs:2:12 + | +LL | #![feature(type_alias_impl_trait)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #63063 for more information + +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-74761-2.rs:9:6 + | +LL | impl<'a, 'b> A for () { + | ^^ unconstrained lifetime parameter + +error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-74761-2.rs:9:10 + | +LL | impl<'a, 'b> A for () { + | ^^ unconstrained lifetime parameter + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0207, E0658. +For more information about an error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs index 38aa18fe40ee7..11756017ad846 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs @@ -5,9 +5,9 @@ #![feature(min_type_alias_impl_trait)] type X = impl ToString; -//~^ ERROR could not find defining uses fn f(a: A, b: B) -> (X, X) { + //~^ ERROR concrete type differs from previous defining opaque type (a.clone(), a) } diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr index c00973c0761b0..52b0462de988c 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr @@ -1,8 +1,14 @@ -error: could not find defining uses - --> $DIR/multiple-def-uses-in-one-fn2.rs:7:52 +error: concrete type differs from previous defining opaque type use + --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1 | -LL | type X = impl ToString; - | ^^^^^^^^^^^^^ +LL | fn f(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `B` + | +note: previous use here + --> $DIR/multiple-def-uses-in-one-fn2.rs:9:1 + | +LL | fn f(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs index 17e900058113d..5f25365666c7f 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs @@ -11,6 +11,7 @@ fn f(a: A, b: B) -> (X, X) } fn g(a: A, b: B) -> (X, X) { + //~^ ERROR concrete type differs from previous defining opaque type (a, b) //~^ ERROR mismatched types } diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr index bbe709dccab4e..3d943b77af57d 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr @@ -1,10 +1,11 @@ error[E0308]: mismatched types - --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9 + --> $DIR/multiple-def-uses-in-one-fn3.rs:15:9 | LL | fn g(a: A, b: B) -> (X, X) { | - - found type parameter | | | expected type parameter +LL | LL | (a, b) | ^ expected type parameter `A`, found type parameter `B` | @@ -13,6 +14,18 @@ LL | (a, b) = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters -error: aborting due to previous error +error: concrete type differs from previous defining opaque type use + --> $DIR/multiple-def-uses-in-one-fn3.rs:13:1 + | +LL | fn g(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `[type error]` + | +note: previous use here + --> $DIR/multiple-def-uses-in-one-fn3.rs:9:1 + | +LL | fn f(a: A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. From df04b98bcc543b89eb54a5ce34a0f0f68e444905 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 10:48:56 +0000 Subject: [PATCH 16/22] Use instrument debugging for more readable logs --- .../rustc_trait_selection/src/opaque_types.rs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 39013a317fd9c..95c81c5c729be 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -83,6 +83,7 @@ pub struct OpaqueTypeDecl<'tcx> { } /// Whether member constraints should be generated for all opaque types +#[derive(Debug)] pub enum GenerateMemberConstraints { /// The default, used by typeck WhenRequired, @@ -354,8 +355,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { opaque_types: &OpaqueTypeMap<'tcx>, free_region_relations: &FRR, ) { - debug!("constrain_opaque_types()"); - for &(opaque_type_key, opaque_defn) in opaque_types { self.constrain_opaque_type( opaque_type_key, @@ -367,6 +366,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } /// See `constrain_opaque_types` for documentation. + #[instrument(level = "debug", skip(self, free_region_relations))] fn constrain_opaque_type>( &self, opaque_type_key: OpaqueTypeKey<'tcx>, @@ -376,15 +376,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { let def_id = opaque_type_key.def_id; - debug!("constrain_opaque_type()"); - debug!("constrain_opaque_type: def_id={:?}", def_id); - debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn); - let tcx = self.tcx; let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty); - debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); + debug!(?concrete_ty); let first_own_region = match opaque_defn.origin { hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => { @@ -397,7 +393,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // type foo::<'p0..'pn>::Foo<'q0..'qm> // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. // - // For these types we onlt iterate over `'l0..lm` below. + // For these types we only iterate over `'l0..lm` below. tcx.generics_of(def_id).parent_count } // These opaque type inherit all lifetime parameters from their @@ -410,10 +406,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If there are required region bounds, we can use them. if opaque_defn.has_required_region_bounds { let bounds = tcx.explicit_item_bounds(def_id); - debug!("constrain_opaque_type: predicates: {:#?}", bounds); + debug!("{:#?}", bounds); let bounds: Vec<_> = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect(); - debug!("constrain_opaque_type: bounds={:#?}", bounds); + debug!("{:#?}", bounds); let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs); let required_region_bounds = @@ -452,8 +448,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; // Compute the least upper bound of it with the other regions. - debug!("constrain_opaque_types: least_region={:?}", least_region); - debug!("constrain_opaque_types: subst_region={:?}", subst_region); + debug!(?least_region); + debug!(?subst_region); match least_region { None => least_region = Some(subst_region), Some(lr) => { @@ -484,7 +480,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } let least_region = least_region.unwrap_or(tcx.lifetimes.re_static); - debug!("constrain_opaque_types: least_region={:?}", least_region); + debug!(?least_region); if let GenerateMemberConstraints::IfNoStaticBound = mode { if least_region != tcx.lifetimes.re_static { From 1ad1b94de73741ebc38bee22a299c11c7bede5a0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 10:53:23 +0000 Subject: [PATCH 17/22] Remove an unnecessary variable --- compiler/rustc_mir/src/borrow_check/type_check/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index de327047a872a..03ffad4a814cb 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1297,7 +1297,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return Ok(()); } - let infcx = self.infcx; let param_env = self.param_env; let body = self.body; let mir_def_id = body.source.def_id().expect_local(); @@ -1380,7 +1379,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations, ConstraintCategory::OpaqueType, CustomTypeOp::new( - |_cx| { + |infcx| { infcx.constrain_opaque_type( opaque_type_key, &opaque_decl, From 07e11e849586c30540dfd784f56438dc7af11900 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 7 Feb 2021 21:50:56 +0000 Subject: [PATCH 18/22] docs: GlobalAlloc: completely replace example with one that works Since this is an example, this could really do with some review from someone familiar with unsafe stuff ! I made the example no longer `no_run` since it works for me. Fixes #81847 Signed-off-by: Ian Jackson Co-authored-by: Amanieu d'Antras --- library/core/src/alloc/global.rs | 67 ++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 6dcc110f1539c..a8e76c2982d22 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -20,24 +20,69 @@ use crate::ptr; /// /// # Example /// -/// ```no_run -/// use std::alloc::{GlobalAlloc, Layout, alloc}; +/// ``` +/// use std::alloc::{GlobalAlloc, Layout}; +/// use std::cell::UnsafeCell; /// use std::ptr::null_mut; +/// use std::sync::atomic::{ +/// AtomicUsize, +/// Ordering::{Acquire, SeqCst}, +/// }; /// -/// struct MyAllocator; -/// -/// unsafe impl GlobalAlloc for MyAllocator { -/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() } -/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// const ARENA_SIZE: usize = 128 * 1024; +/// #[repr(C, align(131072))] // 131072 == ARENA_SIZE. +/// struct SimpleAllocator { +/// arena: UnsafeCell<[u8; ARENA_SIZE]>, +/// remaining: AtomicUsize, // we allocate from the top, counting down /// } /// /// #[global_allocator] -/// static A: MyAllocator = MyAllocator; +/// static ALLOCATOR: SimpleAllocator = SimpleAllocator { +/// arena: UnsafeCell::new([0x55; ARENA_SIZE]), +/// remaining: AtomicUsize::new(ARENA_SIZE), +/// }; /// -/// fn main() { -/// unsafe { -/// assert!(alloc(Layout::new::()).is_null()) +/// unsafe impl Sync for SimpleAllocator {} +/// +/// unsafe impl GlobalAlloc for SimpleAllocator { +/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 { +/// let size = layout.size(); +/// let align = layout.align(); +/// +/// // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2. +/// // So we can safely use a mask to ensure alignment without worrying about UB. +/// let align_mask_to_round_down = !(align - 1); +/// +/// if align > ARENA_SIZE { +/// // align may be > size ! +/// return null_mut(); +/// } +/// +/// let mut allocated = 0; +/// if self +/// .remaining +/// .fetch_update(SeqCst, SeqCst, |mut remaining| { +/// if size > remaining { +/// return None; +/// } +/// remaining -= size; +/// remaining &= align_mask_to_round_down; +/// allocated = remaining; +/// Some(remaining) +/// }) +/// .is_err() +/// { +/// return null_mut(); +/// }; +/// (self.arena.get() as *mut u8).add(allocated) /// } +/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// } +/// +/// fn main() { +/// let _s = format!("allocating a string!"); +/// let currently = ALLOCATOR.remaining.load(Acquire); +/// println!("allocated so far: {}", ARENA_SIZE - currently); /// } /// ``` /// From b3aca4765327b69fb12f87456a63d450fdefbdc4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 15:10:55 +0000 Subject: [PATCH 19/22] Resolve nested inference variables. I attempted that with the previous code, but I misunderstdood how `shallow_resolve` works. --- .../src/borrow_check/type_check/mod.rs | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 03ffad4a814cb..3fb06cd2f5f44 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -182,25 +182,13 @@ pub(crate) fn type_check<'mir, 'tcx>( let mut opaque_type_values = cx.opaque_type_values; for (_, revealed_ty) in &mut opaque_type_values { - // FIXME(oli-obk): Instead of looping, implement a visitor like - // FullTypeResolver. We can't use FullTypeResolver here, as that will - // resolve lifetimes lexically, which it can't because we didn't do old - // borrowck stuff. We want to use MIR borrowck information instead. - - while revealed_ty.has_infer_types_or_consts() { - let prev = *revealed_ty; - trace!(prev=?prev.kind()); - let type_resolved = infcx.shallow_resolve(prev); - trace!(type_resolved=?type_resolved.kind()); - if prev == type_resolved { - infcx.tcx.sess.delay_span_bug( - body.span, - &format!("could not resolve {:#?}", type_resolved.kind()), - ); - *revealed_ty = infcx.tcx.ty_error(); - break; - } - *revealed_ty = type_resolved; + *revealed_ty = infcx.resolve_vars_if_possible(*revealed_ty); + if revealed_ty.has_infer_types_or_consts() { + infcx.tcx.sess.delay_span_bug( + body.span, + &format!("could not resolve {:#?}", revealed_ty.kind()), + ); + *revealed_ty = infcx.tcx.ty_error(); } } From db0324ebb2961bbeb1a75641fd1ca38d6462b721 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 18 Jul 2021 11:33:49 -0500 Subject: [PATCH 20/22] Support HIR wf checking for function signatures During function type-checking, we normalize any associated types in the function signature (argument types + return type), and then create WF obligations for each of the normalized types. The HIR wf code does not currently support this case, so any errors that we get have imprecise spans. This commit extends `ObligationCauseCode::WellFormed` to support recording a function parameter, allowing us to get the corresponding HIR type if an error occurs. Function typechecking is modified to pass this information during signature normalization and WF checking. The resulting code is fairly verbose, due to the fact that we can no longer normalize the entire signature with a single function call. As part of the refactoring, we now perform HIR-based WF checking for several other 'typed items' (statics, consts, and inherent impls). As a result, WF and projection errors in a function signature now have a precise span, which points directly at the responsible type. If a function signature is constructed via a macro, this will allow the error message to point at the code 'most responsible' for the error (e.g. a user-supplied macro argument). --- compiler/rustc_middle/src/hir/map/mod.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 34 +++++-- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_query_impl/src/keys.rs | 4 +- .../src/traits/error_reporting/mod.rs | 4 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 5 +- compiler/rustc_typeck/src/check/wfcheck.rs | 72 +++++++++++++-- compiler/rustc_typeck/src/hir_wf_check.rs | 91 ++++++++++++++----- .../associated-types-for-unimpl-trait.stderr | 7 +- .../associated-types-no-suitable-bound.stderr | 7 +- ...ated-types-no-suitable-supertrait-2.stderr | 7 +- ...ciated-types-no-suitable-supertrait.stderr | 14 ++- ...ted-trait-in-method-without-default.stderr | 7 +- .../object-safety-err-ret.stderr | 4 +- src/test/ui/error-codes/E0038.stderr | 4 +- ...ature-gate-object_safe_for_dispatch.stderr | 8 +- .../gat-in-trait-path.stderr | 4 +- .../issue-67510-pass.stderr | 4 +- .../trait-objects.stderr | 4 +- src/test/ui/issues/issue-18611.stderr | 7 +- src/test/ui/issues/issue-18959.stderr | 4 +- ...object-unsafe-trait-references-self.stderr | 8 +- ...unsafe-trait-should-use-where-sized.stderr | 4 +- src/test/ui/wf/wf-foreign-fn-decl-ret.stderr | 7 +- src/test/ui/wf/wf-in-fn-arg.stderr | 4 +- src/test/ui/wf/wf-trait-default-fn-arg.stderr | 4 +- src/test/ui/wf/wf-trait-fn-arg.stderr | 4 +- 28 files changed, 240 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index ae53f1ac3bb49..392372fad531e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -29,7 +29,10 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl), - Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) => Some(fn_decl), + Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) + | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => { + Some(fn_decl) + } _ => None, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cb99ae19ee72e..0908b6a1763d5 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1722,7 +1722,7 @@ rustc_queries! { /// span) for an *existing* error. Therefore, it is best-effort, and may never handle /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, /// because the `ty::Ty`-based wfcheck is always run. - query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, hir::HirId)) -> Option> { + query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option> { eval_always no_hash desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index f951e43fbfa35..a4a2e82463757 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -16,7 +16,7 @@ use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Constness; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -327,17 +327,39 @@ pub enum ObligationCauseCode<'tcx> { /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` OpaqueType, - /// Well-formed checking. If a `HirId` is provided, - /// it is used to perform HIR-based wf checking if an error - /// occurs, in order to generate a more precise error message. + /// Well-formed checking. If a `WellFormedLoc` is provided, + /// then it will be used to eprform HIR-based wf checking + /// after an error occurs, in order to generate a more precise error span. /// This is purely for diagnostic purposes - it is always - /// correct to use `MiscObligation` instead - WellFormed(Option), + /// correct to use `MiscObligation` instead, or to specify + /// `WellFormed(None)` + WellFormed(Option), /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against. MatchImpl(Lrc>, DefId), } +/// The 'location' at which we try to perform HIR-based wf checking. +/// This information is used to obtain an `hir::Ty`, which +/// we can walk in order to obtain precise spans for any +/// 'nested' types (e.g. `Foo` in `Option`). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +pub enum WellFormedLoc { + /// Use the type of the provided definition. + Ty(LocalDefId), + /// Use the type of the parameter of the provided function. + /// We cannot use `hir::Param`, since the function may + /// not have a body (e.g. a trait method definition) + Param { + /// The function to lookup the parameter in + function: LocalDefId, + /// The index of the parameter to use. + /// Parameters are indexed from 0, with the return type + /// being the last 'parameter' + param_idx: u16, + }, +} + impl ObligationCauseCode<'_> { // Return the base obligation, ignoring derived obligations. pub fn peel_derives(&self) -> &Self { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b84058011066f..4ce49032398bc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1682,7 +1682,7 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} -CloneLiftImpls! { for<'tcx> { Constness, } } +CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 1993e0a602fa5..0ad360c7d89c3 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -1,9 +1,9 @@ //! Defines the set of legal keys that can be used in queries. use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use rustc_hir::HirId; use rustc_middle::infer::canonical::Canonical; use rustc_middle::mir; +use rustc_middle::traits; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -397,7 +397,7 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { } } -impl<'tcx> Key for (ty::Predicate<'tcx>, HirId) { +impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { #[inline(always)] fn query_crate_is_local(&self) -> bool { true diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5c4aef529e5ac..13a6733fb478a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -242,11 +242,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { SelectionError::Unimplemented => { // If this obligation was generated as a result of well-formed checking, see if we // can get a better error message by performing HIR-based well formed checking. - if let ObligationCauseCode::WellFormed(Some(wf_hir_id)) = + if let ObligationCauseCode::WellFormed(Some(wf_loc)) = root_obligation.cause.code.peel_derives() { if let Some(cause) = - self.tcx.diagnostic_hir_wf_check((obligation.predicate, *wf_hir_id)) + self.tcx.diagnostic_hir_wf_check((obligation.predicate, wf_loc.clone())) { obligation.cause = cause; span = obligation.cause.span; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 4ed07ba358de3..865e4ccc0b63f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -40,6 +40,7 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, + WellFormedLoc, }; use std::collections::hash_map::Entry; @@ -419,13 +420,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, value: T, - hir_id: hir::HirId, + loc: WellFormedLoc, ) -> T where T: TypeFoldable<'tcx>, { self.inh.normalize_associated_types_in_with_cause( - ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(hir_id))), + ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(loc))), self.param_env, value, ) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b24d63917c1cf..98980c65bc815 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -22,8 +22,9 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use std::convert::TryInto; use std::iter; use std::ops::ControlFlow; @@ -386,7 +387,7 @@ fn check_associated_item( span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - let code = ObligationCauseCode::WellFormed(Some(item_id)); + let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))); for_id(tcx, item_id, span).with_fcx(|fcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); @@ -400,7 +401,11 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); + let ty = fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { @@ -422,7 +427,11 @@ fn check_associated_item( } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); + let ty = fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -621,7 +630,11 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo for_id(tcx, item_id, ty_span).with_fcx(|fcx| { let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, item_id); + let item_ty = fcx.normalize_associated_types_in_wf( + ty_span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); let mut forbid_unsized = true; if allow_foreign_ty { @@ -634,7 +647,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo fcx.register_wf_obligation( item_ty.into(), ty_span, - ObligationCauseCode::WellFormed(Some(item_id)), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))), ); if forbid_unsized { fcx.register_bound( @@ -684,7 +697,9 @@ fn check_impl<'tcx>( fcx.register_wf_obligation( self_ty.into(), ast_self_ty.span, - ObligationCauseCode::WellFormed(Some(item.hir_id())), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty( + item.hir_id().expect_owner(), + ))), ); } } @@ -901,11 +916,48 @@ fn check_fn_or_method<'fcx, 'tcx>( implied_bounds: &mut Vec>, ) { let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); - let sig = fcx.normalize_associated_types_in(span, sig); - for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) { - fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::WellFormed(None)); + // Normalize the input and output types one at a time, using a different + // `WellFormedLoc` for each. We cannot call `normalize_associated_types` + // on the entire `FnSig`, since this would use the same `WellFormedLoc` + // for each type, preventing the HIR wf check from generating + // a nice error message. + let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig; + inputs_and_output = + fcx.tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { + fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Param { + function: def_id.expect_local(), + // Note that the `param_idx` of the output type is + // one greater than the index of the last input type. + param_idx: i.try_into().unwrap(), + }, + ) + })); + // Manually call `normalize_assocaited_types_in` on the other types + // in `FnSig`. This ensures that if the types of these fields + // ever change to include projections, we will start normalizing + // them automatically. + let sig = ty::FnSig { + inputs_and_output, + c_variadic: fcx.normalize_associated_types_in(span, c_variadic), + unsafety: fcx.normalize_associated_types_in(span, unsafety), + abi: fcx.normalize_associated_types_in(span, abi), + }; + + for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() { + fcx.register_wf_obligation( + input_ty.into(), + ty.span, + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param { + function: def_id.expect_local(), + param_idx: i.try_into().unwrap(), + })), + ); } + implied_bounds.extend(sig.inputs()); fcx.register_wf_obligation( diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index a8ec7b79e571f..c1af10f5ce451 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -3,10 +3,10 @@ use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::HirId; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::ObligationCause; use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, ToPredicate, TyCtxt}; +use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder}; use rustc_trait_selection::traits; pub fn provide(providers: &mut Providers) { @@ -17,21 +17,20 @@ pub fn provide(providers: &mut Providers) { // need access to `ItemCtxt` fn diagnostic_hir_wf_check<'tcx>( tcx: TyCtxt<'tcx>, - (predicate, hir_id): (ty::Predicate<'tcx>, HirId), + (predicate, loc): (ty::Predicate<'tcx>, WellFormedLoc), ) -> Option> { let hir = tcx.hir(); - // HIR wfcheck should only ever happen as part of improving an existing error - tcx.sess.delay_span_bug(hir.span(hir_id), "Performed HIR wfcheck without an existing error!"); - // Currently, we only handle WF checking for items (e.g. associated items). - // It would be nice to extend this to handle wf checks inside functions. - let def_id = match tcx.hir().opt_local_def_id(hir_id) { - Some(def_id) => def_id, - None => return None, + let def_id = match loc { + WellFormedLoc::Ty(def_id) => def_id, + WellFormedLoc::Param { function, param_idx: _ } => function, }; + let hir_id = HirId::make_owner(def_id); + + // HIR wfcheck should only ever happen as part of improving an existing error + tcx.sess + .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!"); - // FIXME - figure out how we want to handle wf-checking for - // things inside a function body. let icx = ItemCtxt::new(tcx, def_id.to_def_id()); // To perform HIR-based WF checking, we iterate over all HIR types @@ -72,7 +71,8 @@ fn diagnostic_hir_wf_check<'tcx>( fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { self.tcx.infer_ctxt().enter(|infcx| { let mut fulfill = traits::FulfillmentContext::new(); - let tcx_ty = self.icx.to_ty(ty); + let tcx_ty = + self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( ty.span, self.hir_id, @@ -119,19 +119,66 @@ fn diagnostic_hir_wf_check<'tcx>( depth: 0, }; - let ty = match tcx.hir().get(hir_id) { - hir::Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::TyAlias(ty) => Some(ty), - _ => None, - }, - hir::Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Type(_, ty) => ty, - _ => None, + // Get the starting `hir::Ty` using our `WellFormedLoc`. + // We will walk 'into' this type to try to find + // a more precise span for our predicate. + let ty = match loc { + WellFormedLoc::Ty(_) => match hir.get(hir_id) { + hir::Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::TyAlias(ty) => Some(ty), + ref item => bug!("Unexpected ImplItem {:?}", item), + }, + hir::Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Type(_, ty) => ty, + ref item => bug!("Unexpected TraitItem {:?}", item), + }, + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty), + hir::ItemKind::Impl(ref impl_) => { + assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_); + Some(impl_.self_ty) + } + ref item => bug!("Unexpected item {:?}", item), + }, + ref node => bug!("Unexpected node {:?}", node), }, - _ => None, + WellFormedLoc::Param { function: _, param_idx } => { + let fn_decl = hir.fn_decl_by_hir_id(hir_id).unwrap(); + // Get return type + if param_idx as usize == fn_decl.inputs.len() { + match fn_decl.output { + hir::FnRetTy::Return(ty) => Some(ty), + // The unit type `()` is always well-formed + hir::FnRetTy::DefaultReturn(_span) => None, + } + } else { + Some(&fn_decl.inputs[param_idx as usize]) + } + } }; if let Some(ty) = ty { visitor.visit_ty(ty); } visitor.cause } + +struct EraseAllBoundRegions<'tcx> { + tcx: TyCtxt<'tcx>, +} + +// Higher ranked regions are complicated. +// To make matters worse, the HIR WF check can instantiate them +// outside of a `Binder`, due to the way we (ab)use +// `ItemCtxt::to_ty`. To make things simpler, we just erase all +// of them, regardless of depth. At worse, this will give +// us an inaccurate span for an error message, but cannot +// lead to unsoundess (we call `delay_span_bug` at the start +// of `diagnostic_hir_wf_check`). +impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { + if let ty::ReLateBound(..) = r { &ty::ReErased } else { r } + } +} diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr index e8c11a32bf7fd..25e80159b0b18 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-for-unimpl-trait.rs:10:8 + --> $DIR/associated-types-for-unimpl-trait.rs:10:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr index e3be434698ab9..19500f58aa688 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `T: Get` is not satisfied - --> $DIR/associated-types-no-suitable-bound.rs:11:8 + --> $DIR/associated-types-no-suitable-bound.rs:11:21 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(foo: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr index 9dc3414e9edf0..0e978f20a6634 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:8 + --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr index c2aed3f9de548..1ec3c05983aef 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:17:8 + --> $DIR/associated-types-no-suitable-supertrait.rs:17:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | @@ -10,10 +13,13 @@ LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Ge | ^^^^^^^^^^^^^^^ error[E0277]: the trait bound `(T, U): Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:22:8 + --> $DIR/associated-types-no-suitable-supertrait.rs:22:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} - | ^^^^ the trait `Get` is not implemented for `(T, U)` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index fb842d968676d..b6ee1ed733c3e 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:8 + --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn okay(&self, foo: U, bar: ::Value); - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr index e0e6029252c00..319e6c2c032a0 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-ret.rs:17:15 + --> $DIR/object-safety-err-ret.rs:17:16 | LL | fn use_dyn(v: &dyn Foo) { - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` cannot be made into an object | = help: consider moving `test` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/error-codes/E0038.stderr b/src/test/ui/error-codes/E0038.stderr index eb68a6298d1ac..cead9776e4abb 100644 --- a/src/test/ui/error-codes/E0038.stderr +++ b/src/test/ui/error-codes/E0038.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/E0038.rs:5:16 + --> $DIR/E0038.rs:5:20 | LL | fn call_foo(x: Box) { - | ^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr index 12195bc1071a0..c13c05f146a7e 100644 --- a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `NonObjectSafe1` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:38 + --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:39 | LL | fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { - | ^^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23 @@ -35,10 +35,10 @@ LL | fn static_fn() where Self: Sized {} | ^^^^^^^^^^^^^^^^^ error[E0038]: the trait `NonObjectSafe3` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:35 + --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:39 | LL | fn takes_non_object_safe_box(obj: Box) { - | ^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr index eb8e101a83d79..8651789688eaa 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/gat-in-trait-path.rs:21:13 + --> $DIR/gat-in-trait-path.rs:21:17 | LL | fn f(_arg : Box Foo = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | = help: consider moving `A` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr index 8cc9f2816a166..b4b89ab047363 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.stderr +++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `X` cannot be made into an object - --> $DIR/issue-67510-pass.rs:7:19 + --> $DIR/issue-67510-pass.rs:7:23 | LL | fn _func1<'a>(_x: Box=&'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | = help: consider moving `Y` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/trait-objects.stderr b/src/test/ui/generic-associated-types/trait-objects.stderr index a121566bbd884..6429bb8159e1f 100644 --- a/src/test/ui/generic-associated-types/trait-objects.stderr +++ b/src/test/ui/generic-associated-types/trait-objects.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `StreamingIterator` cannot be made into an object - --> $DIR/trait-objects.rs:10:16 + --> $DIR/trait-objects.rs:10:21 | LL | fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object | = help: consider moving `Item` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/issues/issue-18611.stderr b/src/test/ui/issues/issue-18611.stderr index 8872f51753c94..0e942e80e2544 100644 --- a/src/test/ui/issues/issue-18611.stderr +++ b/src/test/ui/issues/issue-18611.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `isize: HasState` is not satisfied - --> $DIR/issue-18611.rs:1:4 + --> $DIR/issue-18611.rs:1:18 | LL | fn add_state(op: ::State) { - | ^^^^^^^^^ the trait `HasState` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize` +... +LL | trait HasState { + | -------------- required by this bound in `HasState` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18959.stderr b/src/test/ui/issues/issue-18959.stderr index 86b530e85a80a..2a5416ce85ba6 100644 --- a/src/test/ui/issues/issue-18959.stderr +++ b/src/test/ui/issues/issue-18959.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-18959.rs:11:11 + --> $DIR/issue-18959.rs:11:12 | LL | fn foo(b: &dyn Bar) { - | ^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr index 797406f869fe6..f332b7213d8bc 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:6:11 + --> $DIR/object-unsafe-trait-references-self.rs:6:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | = help: consider moving `baz` to another trait = help: consider moving `bat` to another trait @@ -17,10 +17,10 @@ LL | fn bat(&self) -> Self {} | ^^^^ ...because method `bat` references the `Self` type in its return type error[E0038]: the trait `Other` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:10:11 + --> $DIR/object-unsafe-trait-references-self.rs:10:12 | LL | fn foo(x: &dyn Other) {} - | ^^^^^^^^^^ `Other` cannot be made into an object + | ^^^^^^^^^ `Other` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-references-self.rs:8:14 diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr index a2caf846cc5fe..4c18f6d79d077 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:11 + --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-where-sized.rs:5:8 diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr index a0eb7d10bd94a..f6b48938f9b04 100644 --- a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr +++ b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/wf-foreign-fn-decl-ret.rs:11:12 + --> $DIR/wf-foreign-fn-decl-ret.rs:11:25 | +LL | pub trait Foo { + | ------------- required by this bound in `Foo` +... LL | pub fn lint_me() -> <() as Foo>::Assoc; - | ^^^^^^^ the trait `Foo` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied --> $DIR/wf-foreign-fn-decl-ret.rs:14:32 diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index 9687658feba43..ca90e9222dea9 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/wf-in-fn-arg.rs:10:14 + --> $DIR/wf-in-fn-arg.rs:10:15 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | fn bar(_: &MustBeCopy) - | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index c3d5d2b9669b8..2a129538f7633 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-default-fn-arg.rs:11:22 + --> $DIR/wf-trait-default-fn-arg.rs:11:23 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar) { - | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr index 4510f50feea58..7693aa6d2d583 100644 --- a/src/test/ui/wf/wf-trait-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-fn-arg.rs:10:22 + --> $DIR/wf-trait-fn-arg.rs:10:23 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar); - | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | From 713044c652a8dc9815df97e1f7a6d167bd22d88c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 20 Jul 2021 15:16:41 +0000 Subject: [PATCH 21/22] Add a regression test --- src/test/ui/impl-trait/issue-86465.rs | 10 ++++++++++ src/test/ui/impl-trait/issue-86465.stderr | 14 ++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-86465.rs create mode 100644 src/test/ui/impl-trait/issue-86465.stderr diff --git a/src/test/ui/impl-trait/issue-86465.rs b/src/test/ui/impl-trait/issue-86465.rs new file mode 100644 index 0000000000000..23a3748c12c6a --- /dev/null +++ b/src/test/ui/impl-trait/issue-86465.rs @@ -0,0 +1,10 @@ +#![feature(min_type_alias_impl_trait)] + +type X<'a, 'b> = impl std::fmt::Debug; + +fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) { + //~^ ERROR concrete type differs from previous defining opaque type use + (a, a) +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-86465.stderr b/src/test/ui/impl-trait/issue-86465.stderr new file mode 100644 index 0000000000000..595b16aa68554 --- /dev/null +++ b/src/test/ui/impl-trait/issue-86465.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/issue-86465.rs:5:1 + | +LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&'a u32`, got `&'b u32` + | +note: previous use here + --> $DIR/issue-86465.rs:5:1 + | +LL | fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 919a8a5028e4b94370e9c3f6b19cda48f9c97f7b Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 16 Jul 2021 19:18:50 +0800 Subject: [PATCH 22/22] Fix NixOS detection Use `/etc/os-release` instead of `/etc/NIXOS`. The latter one does not exist on NixOS when using tmpfs as root. --- src/bootstrap/bootstrap.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index f9904cb610d2d..1c5e9d5d83736 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -580,7 +580,13 @@ def fix_bin_or_dylib(self, fname): if ostype != "Linux": return - if not os.path.exists("/etc/NIXOS"): + # Use `/etc/os-release` instead of `/etc/NIXOS`. + # The latter one does not exist on NixOS when using tmpfs as root. + try: + with open("/etc/os-release", "r") as f: + if not any(line.strip() == "ID=nixos" for line in f): + return + except FileNotFoundError: return if os.path.exists("/lib"): return