From 76e09eb87a0ae8dbbd54d14ba4d5186ffbd1513a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 6 Sep 2021 13:16:47 -0400 Subject: [PATCH 01/32] Do not unshallow -- already done by other code backport-of: none --- src/ci/scripts/verify-backported-commits.sh | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/ci/scripts/verify-backported-commits.sh b/src/ci/scripts/verify-backported-commits.sh index 1023e4b0e2837..d3da6d1ac915a 100755 --- a/src/ci/scripts/verify-backported-commits.sh +++ b/src/ci/scripts/verify-backported-commits.sh @@ -18,14 +18,6 @@ verify_backported_commits_main() { exit 0 fi - echo 'git: unshallowing the repository so we can check commits' - git fetch \ - --no-tags \ - --no-recurse-submodules \ - --progress \ - --prune \ - --unshallow - if [[ $ci_base_branch == "beta" ]]; then verify_cherries master "$BETA_LIMIT" \ || exit 1 From af9de99f1262ae0b42e9e4a7d0cf56fa1e429827 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 25 Aug 2021 13:43:00 -0400 Subject: [PATCH 02/32] Detect stricter constraints on gats where clauses in impls vs trait --- .../trait_impl_difference.rs | 87 ++++++++++++------- .../src/infer/error_reporting/note.rs | 18 ++++ compiler/rustc_infer/src/infer/mod.rs | 21 +++++ .../generic-associated-types/impl_bounds.rs | 3 +- .../impl_bounds.stderr | 35 ++++---- .../issue-86787.stderr | 4 +- .../missing-where-clause-on-trait.rs | 14 +++ .../missing-where-clause-on-trait.stderr | 21 +++++ 8 files changed, 153 insertions(+), 50 deletions(-) create mode 100644 src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs create mode 100644 src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 61c8113d05287..4d789d2309136 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -2,7 +2,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::{Subtype, ValuePairs}; +use crate::infer::{SubregionOrigin, Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_errors::ErrorReported; use rustc_hir as hir; @@ -11,44 +11,52 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{MultiSpan, Span}; +use rustc_span::{MultiSpan, Span, Symbol}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option { - if let Some(ref error) = self.error { - debug!("try_report_impl_not_conforming_to_trait {:?}", error); - if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - _sub, - sup_origin, - _sup, - ) = error.clone() - { - if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = - (&sup_origin, &sub_origin) + let error = self.error.as_ref()?; + debug!("try_report_impl_not_conforming_to_trait {:?}", error); + if let RegionResolutionError::SubSupConflict( + _, + var_origin, + sub_origin, + _sub, + sup_origin, + _sup, + ) = error.clone() + { + if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) { + if let ( + ValuePairs::Types(sub_expected_found), + ValuePairs::Types(sup_expected_found), + CompareImplMethodObligation { trait_item_def_id, .. }, + ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) { - if let ( - ValuePairs::Types(sub_expected_found), - ValuePairs::Types(sup_expected_found), - CompareImplMethodObligation { trait_item_def_id, .. }, - ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) - { - if sup_expected_found == sub_expected_found { - self.emit_err( - var_origin.span(), - sub_expected_found.expected, - sub_expected_found.found, - *trait_item_def_id, - ); - return Some(ErrorReported); - } + if sup_expected_found == sub_expected_found { + self.emit_err( + var_origin.span(), + sub_expected_found.expected, + sub_expected_found.found, + *trait_item_def_id, + ); + return Some(ErrorReported); } } } } + if let RegionResolutionError::ConcreteFailure(origin, _, _) = error.clone() { + if let SubregionOrigin::CompareImplTypeObligation { + span, + item_name, + impl_item_def_id, + trait_item_def_id, + } = origin + { + self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id); + } + } None } @@ -107,6 +115,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } err.emit(); } + + fn emit_associated_type_err( + &self, + span: Span, + item_name: Symbol, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + ) { + let impl_sp = self.tcx().def_span(impl_item_def_id); + let trait_sp = self.tcx().def_span(trait_item_def_id); + let mut err = self + .tcx() + .sess + .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name)); + err.span_label(impl_sp, &format!("found")); + err.span_label(trait_sp, &format!("expected")); + + err.emit(); + } } struct TypeParamSpanVisitor<'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 4bc59a4baf5ca..5f99a23f86e88 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -99,6 +99,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...so that the definition in impl matches the definition from the trait", ); } + infer::CompareImplTypeObligation { span, .. } => { + label_or_note( + span, + "...so that the definition in impl matches the definition from the trait", + ); + } } } @@ -356,6 +362,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_item_def_id, &format!("`{}: {}`", sup, sub), ), + infer::CompareImplTypeObligation { + span, + item_name, + impl_item_def_id, + trait_item_def_id, + } => self.report_extra_impl_obligation( + span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + ), } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index bc98a3aa3f95e..354b8e26d53d5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -427,6 +427,15 @@ pub enum SubregionOrigin<'tcx> { impl_item_def_id: DefId, trait_item_def_id: DefId, }, + + /// Comparing the signature and requirements of an impl associated type + /// against the containing trait + CompareImplTypeObligation { + span: Span, + item_name: Symbol, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -1810,6 +1819,7 @@ impl<'tcx> SubregionOrigin<'tcx> { ReferenceOutlivesReferent(_, a) => a, CallReturn(a) => a, CompareImplMethodObligation { span, .. } => span, + CompareImplTypeObligation { span, .. } => span, } } @@ -1833,6 +1843,17 @@ impl<'tcx> SubregionOrigin<'tcx> { trait_item_def_id, }, + traits::ObligationCauseCode::CompareImplTypeObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CompareImplTypeObligation { + span: cause.span, + item_name, + impl_item_def_id, + trait_item_def_id, + }, + _ => default(), } } diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index 01edad00a89f1..2b52483d1d6a1 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -15,7 +15,8 @@ impl Foo for Fooy { type A<'a> where Self: 'static = (&'a ()); //~^ ERROR the parameter type `T` may not live long enough type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - //~^ ERROR lifetime bound not satisfied + //~^ ERROR `impl` associated type + //~| ERROR impl has stricter //~| ERROR lifetime bound not satisfied type C where Self: Copy = String; //~^ ERROR the trait bound `T: Copy` is not satisfied diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 8cf923ca3ac0c..38c7ca7a1a195 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -5,24 +5,25 @@ LL | type A<'a> where Self: 'static = (&'a ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `Fooy` will meet its required lifetime bounds + = note: ...so that the definition in impl matches the definition from the trait -error[E0478]: lifetime bound not satisfied +error: `impl` associated type signature for `B` doesn't match `trait` associated type signature --> $DIR/impl_bounds.rs:17:5 | +LL | type B<'a, 'b> where 'a: 'b; + | ---------------------------- expected +... LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lifetime parameter instantiated with the lifetime `'b` as defined on the associated item at 17:16 - --> $DIR/impl_bounds.rs:17:16 - | -LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^ -note: but lifetime parameter must outlive the lifetime `'a` as defined on the associated item at 17:12 - --> $DIR/impl_bounds.rs:17:12 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + +error[E0276]: impl has stricter requirements than trait + --> $DIR/impl_bounds.rs:17:5 | +LL | type B<'a, 'b> where 'a: 'b; + | ---------------------------- definition of `B` from trait +... LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'b: 'a` error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:5 @@ -42,7 +43,7 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:20:5 + --> $DIR/impl_bounds.rs:21:5 | LL | type C where Self: Copy = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -67,7 +68,7 @@ LL | impl Foo for Fooy { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:22:5 + --> $DIR/impl_bounds.rs:23:5 | LL | fn d() where Self: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -91,7 +92,7 @@ help: consider restricting type parameter `T` LL | impl Foo for Fooy { | +++++++++++++++++++ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0277, E0310, E0478. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277, E0310, E0478. +For more information about an error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index 04cd84b08011c..e1ff772921104 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -9,7 +9,7 @@ LL | | ::T: 'a, LL | | ::T: 'a | | - help: consider adding a where clause: `, ::T: 'a` LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ ...so that the type `::T` will meet its required lifetime bounds + | |________________________________________^ ...so that the definition in impl matches the definition from the trait error[E0309]: the associated type `::T` may not live long enough --> $DIR/issue-86787.rs:23:5 @@ -22,7 +22,7 @@ LL | | ::T: 'a, LL | | ::T: 'a | | - help: consider adding a where clause: `, ::T: 'a` LL | | = Either<&'a Left::T, &'a Right::T>; - | |________________________________________^ ...so that the type `::T` will meet its required lifetime bounds + | |________________________________________^ ...so that the definition in impl matches the definition from the trait error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs new file mode 100644 index 0000000000000..fa846516040f3 --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs @@ -0,0 +1,14 @@ +// check-fail + +#![feature(generic_associated_types)] + +trait Foo { + type Assoc<'a, 'b>; +} +impl Foo for () { + type Assoc<'a, 'b> where 'a: 'b = (); + //~^ `impl` associated type + //~| impl has stricter +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr new file mode 100644 index 0000000000000..d582099500256 --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr @@ -0,0 +1,21 @@ +error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature + --> $DIR/missing-where-clause-on-trait.rs:9:5 + | +LL | type Assoc<'a, 'b>; + | ------------------- expected +... +LL | type Assoc<'a, 'b> where 'a: 'b = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + +error[E0276]: impl has stricter requirements than trait + --> $DIR/missing-where-clause-on-trait.rs:9:5 + | +LL | type Assoc<'a, 'b>; + | ------------------- definition of `Assoc` from trait +... +LL | type Assoc<'a, 'b> where 'a: 'b = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0276`. From 890de33e4f92c449ca6f142eeb7a7ab945ae5e27 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 7 Sep 2021 18:51:24 -0400 Subject: [PATCH 03/32] Fix duplicate error --- .../trait_impl_difference.rs | 1 + .../generic-associated-types/impl_bounds.rs | 1 - .../impl_bounds.stderr | 19 +++++-------------- .../missing-where-clause-on-trait.rs | 1 - .../missing-where-clause-on-trait.stderr | 12 +----------- 5 files changed, 7 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4d789d2309136..43aa8a6efcec4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -55,6 +55,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } = origin { self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id); + return Some(ErrorReported); } } None diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index 2b52483d1d6a1..27c135cb7cf82 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -16,7 +16,6 @@ impl Foo for Fooy { //~^ ERROR the parameter type `T` may not live long enough type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); //~^ ERROR `impl` associated type - //~| ERROR impl has stricter //~| ERROR lifetime bound not satisfied type C where Self: Copy = String; //~^ ERROR the trait bound `T: Copy` is not satisfied diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 38c7ca7a1a195..73415e0faac88 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -16,15 +16,6 @@ LL | type B<'a, 'b> where 'a: 'b; LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found -error[E0276]: impl has stricter requirements than trait - --> $DIR/impl_bounds.rs:17:5 - | -LL | type B<'a, 'b> where 'a: 'b; - | ---------------------------- definition of `B` from trait -... -LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'b: 'a` - error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:5 | @@ -43,7 +34,7 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:21:5 + --> $DIR/impl_bounds.rs:20:5 | LL | type C where Self: Copy = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -68,7 +59,7 @@ LL | impl Foo for Fooy { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:23:5 + --> $DIR/impl_bounds.rs:22:5 | LL | fn d() where Self: Copy {} | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` @@ -92,7 +83,7 @@ help: consider restricting type parameter `T` LL | impl Foo for Fooy { | +++++++++++++++++++ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0276, E0277, E0310, E0478. -For more information about an error, try `rustc --explain E0276`. +Some errors have detailed explanations: E0277, E0310, E0478. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs index fa846516040f3..ad9f2e3e4ec4a 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs @@ -8,7 +8,6 @@ trait Foo { impl Foo for () { type Assoc<'a, 'b> where 'a: 'b = (); //~^ `impl` associated type - //~| impl has stricter } fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr index d582099500256..0e183c8d69a4c 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr @@ -7,15 +7,5 @@ LL | type Assoc<'a, 'b>; LL | type Assoc<'a, 'b> where 'a: 'b = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found -error[E0276]: impl has stricter requirements than trait - --> $DIR/missing-where-clause-on-trait.rs:9:5 - | -LL | type Assoc<'a, 'b>; - | ------------------- definition of `Assoc` from trait -... -LL | type Assoc<'a, 'b> where 'a: 'b = (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0276`. From c9d46eb2244d49215e0a1ccf8bd4b7e700b252e7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Nov 2020 09:26:10 -0500 Subject: [PATCH 04/32] Rework DepthFirstSearch API This expands the API to be more flexible, allowing for more visitation patterns on graphs. This will be useful to avoid extra datasets (and allocations) in cases where the expanded DFS API is sufficient. This also fixes a bug with the previous DFS constructor, which left the start node not marked as visited (even though it was immediately returned). --- .../src/graph/iterate/mod.rs | 54 ++++++++++++++++++- .../src/graph/iterate/tests.rs | 16 ++++++ .../rustc_data_structures/src/graph/mod.rs | 2 +- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 09b91083a6347..a9db3497b2390 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -83,8 +83,58 @@ impl DepthFirstSearch<'graph, G> where G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, { - pub fn new(graph: &'graph G, start_node: G::Node) -> Self { - Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) } + pub fn new(graph: &'graph G) -> Self { + Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } + } + + /// Version of `push_start_node` that is convenient for chained + /// use. + pub fn with_start_node(mut self, start_node: G::Node) -> Self { + self.push_start_node(start_node); + self + } + + /// Pushes another start node onto the stack. If the node + /// has not already been visited, then you will be able to + /// walk its successors (and so forth) after the current + /// contents of the stack are drained. If multiple start nodes + /// are added into the walk, then their mutual successors + /// will all be walked. You can use this method once the + /// iterator has been completely drained to add additional + /// start nodes. + pub fn push_start_node(&mut self, start_node: G::Node) { + if self.visited.insert(start_node) { + self.stack.push(start_node); + } + } + + /// Searches all nodes reachable from the current start nodes. + /// This is equivalent to just invoke `next` repeatedly until + /// you get a `None` result. + pub fn complete_search(&mut self) { + while let Some(_) = self.next() {} + } + + /// Returns true if node has been visited thus far. + /// A node is considered "visited" once it is pushed + /// onto the internal stack; it may not yet have been yielded + /// from the iterator. This method is best used after + /// the iterator is completely drained. + pub fn visited(&self, node: G::Node) -> bool { + self.visited.contains(node) + } +} + +impl std::fmt::Debug for DepthFirstSearch<'_, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut f = fmt.debug_set(); + for n in self.visited.iter() { + f.entry(&n); + } + f.finish() } } diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs index 0e038e88b221d..c498c289337f1 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs @@ -20,3 +20,19 @@ fn is_cyclic() { assert!(!is_cyclic(&diamond_acyclic)); assert!(is_cyclic(&diamond_cyclic)); } + +#[test] +fn dfs() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + + let result: Vec = DepthFirstSearch::new(&graph).with_start_node(0).collect(); + assert_eq!(result, vec![0, 2, 3, 1]); +} + +#[test] +fn dfs_debug() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + let mut dfs = DepthFirstSearch::new(&graph).with_start_node(0); + dfs.complete_search(); + assert_eq!(format!("{{0, 1, 2, 3}}"), format!("{:?}", dfs)); +} diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index dff22855629a8..3560df6e5e204 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -32,7 +32,7 @@ where where Self: WithNumNodes, { - iterate::DepthFirstSearch::new(self, from) + iterate::DepthFirstSearch::new(self).with_start_node(from) } } From 2987f4ba42b002c58ae485f7ae528cb29c3b1611 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 02:27:41 +0100 Subject: [PATCH 05/32] WIP state --- .../rustc_middle/src/mir/abstract_const.rs | 1 + compiler/rustc_mir_build/src/build/mod.rs | 8 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 + compiler/rustc_mir_build/src/thir/cx/mod.rs | 1 + compiler/rustc_privacy/src/lib.rs | 7 +- .../src/traits/const_evaluatable.rs | 360 +++++++----------- .../src/traits/object_safety.rs | 7 +- 7 files changed, 160 insertions(+), 227 deletions(-) diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index 1ef10241143b8..e75f084e79e21 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -17,6 +17,7 @@ pub enum Node<'tcx> { Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), + Block(&'tcx [NodeId], Option), Cast(CastKind, NodeId, Ty<'tcx>), } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 0a760a740dcae..390ce59cb489c 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -28,6 +28,7 @@ crate fn mir_built<'tcx>( if let Some(def) = def.try_upgrade(tcx) { return tcx.mir_built(def); } + debug!("mir_built: def={:?}", def); let mut body = mir_build(tcx, def); if def.const_param_did.is_some() { @@ -40,6 +41,7 @@ crate fn mir_built<'tcx>( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { + debug!("mir_build: def={:?}", def); let id = tcx.hir().local_def_id_to_hir_id(def.did); let body_owner_kind = tcx.hir().body_owner_kind(id); let typeck_results = tcx.typeck_opt_const_arg(def); @@ -47,10 +49,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // Ensure unsafeck is ran before we steal the THIR. match def { ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { - tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)) + tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)); + tcx.ensure().mir_abstract_const_of_const_arg((did, const_param_did)); } ty::WithOptConstParam { did, const_param_did: None } => { - tcx.ensure().thir_check_unsafety(did) + tcx.ensure().thir_check_unsafety(did); + tcx.ensure().mir_abstract_const(did); } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 66005be05df75..70a5a9286b0b3 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -149,7 +149,9 @@ impl<'tcx> Cx<'tcx> { } fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { + debug!("Expr::make_mirror_unadjusted: expr={:?}", expr); let expr_ty = self.typeck_results().expr_ty(expr); + debug!("Expr::make_mirror_unadjusted: expr_ty={:?}", expr_ty); let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let kind = match expr.kind { @@ -762,6 +764,7 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Err => unreachable!(), }; + debug!("Expr::make_mirror_unadjusted: finish"); Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5059dd939d92d..5310efbccd655 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -20,6 +20,7 @@ crate fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: ty::WithOptConstParam, ) -> (&'tcx Steal>, ExprId) { + debug!("thir_body: {:?}", owner_def); let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did))); let mut cx = Cx::new(tcx, owner_def); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 35e25e52dc5f9..26e1c3e7b8cf4 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,9 +159,10 @@ where self.visit_const(leaf) } ACNode::Cast(_, _, ty) => self.visit_ty(ty), - ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } + ACNode::Block(_, _) + | ACNode::Binop(..) + | ACNode::UnaryOp(..) + | ACNode::FunctionCall(_, _) => ControlFlow::CONTINUE, }) } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index ddabe5967d79c..4e11fefdc81f3 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,14 +8,15 @@ //! In this case we try to build an abstract representation of this constant using //! `mir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. +use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; +use rustc_middle::mir; use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; +use rustc_middle::thir; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -101,9 +102,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } + Node::Block(_, _) + | Node::Binop(_, _, _) + | Node::UnaryOp(_, _) + | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }); match failure_kind { @@ -232,7 +234,8 @@ struct WorkNode<'tcx> { struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + body_id: thir::ExprId, + body: Lrc<&'a thir::Thir<'tcx>>, /// The current WIP node tree. /// /// We require all nodes to be used in the final abstract const, @@ -240,18 +243,18 @@ struct AbstractConstBuilder<'a, 'tcx> { /// if they are mentioned in an assert, so some used nodes are never /// actually reachable by walking the [`AbstractConst`]. nodes: IndexVec>, - locals: IndexVec, - /// We only allow field accesses if they access - /// the result of a checked operation. - checked_op_locals: BitSet, } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { + fn root_span(&self) -> Span { + self.body.exprs[self.body_id].span + } + fn error(&mut self, span: Option, msg: &str) -> Result { self.tcx .sess - .struct_span_err(self.body.span, "overly complex generic constant") - .span_label(span.unwrap_or(self.body.span), msg) + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span.unwrap_or(self.root_span()), msg) .help("consider moving this anonymous constant into a `const` function") .emit(); @@ -260,28 +263,12 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn new( tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), ) -> Result>, ErrorReported> { - let mut builder = AbstractConstBuilder { - tcx, - body, - nodes: IndexVec::new(), - locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), - checked_op_locals: BitSet::new_empty(body.local_decls.len()), - }; - - // We don't have to look at concrete constants, as we - // can just evaluate them. - if !body.is_polymorphic { - return Ok(None); - } + let builder = + AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() }; - // We only allow consts without control flow, so - // we check for cycles here which simplifies the - // rest of this implementation. - if body.is_cfg_cyclic() { - builder.error(None, "cyclic anonymous constants are forbidden")?; - } + // FIXME non-constants should return Ok(None) Ok(Some(builder)) } @@ -301,6 +288,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes[func].used = true; nodes.iter().for_each(|&n| self.nodes[n].used = true); } + Node::Block(stmts, opt_expr) => { + stmts.iter().for_each(|&id| self.nodes[id].used = true); + opt_expr.map(|e| self.nodes[e].used = true); + } Node::Cast(_, operand, _) => { self.nodes[operand].used = true; } @@ -310,50 +301,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes.push(WorkNode { node, span, used: false }) } - fn place_to_local( - &mut self, - span: Span, - p: &mir::Place<'tcx>, - ) -> Result { - const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); - // Do not allow any projections. - // - // One exception are field accesses on the result of checked operations, - // which are required to support things like `1 + 2`. - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - Ok(p) - } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { - // Only allow field accesses if the given local - // contains the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - Ok(p.local) - } else { - self.error(Some(span), "unsupported projection")?; - } - } else { - self.error(Some(span), "unsupported projection")?; - } - } - - fn operand_to_node( - &mut self, - span: Span, - op: &mir::Operand<'tcx>, - ) -> Result { - debug!("operand_to_node: op={:?}", op); - match op { - mir::Operand::Copy(p) | mir::Operand::Move(p) => { - let local = self.place_to_local(span, p)?; - Ok(self.locals[local]) - } - mir::Operand::Constant(ct) => match ct.literal { - mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), - mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?, - }, - } - } - /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; @@ -373,148 +320,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { - debug!("AbstractConstBuilder: stmt={:?}", stmt); - let span = stmt.source_info.span; - match stmt.kind { - StatementKind::Assign(box (ref place, ref rvalue)) => { - let local = self.place_to_local(span, place)?; - match *rvalue { - Rvalue::Use(ref operand) => { - self.locals[local] = self.operand_to_node(span, operand)?; - Ok(()) - } - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) if Self::check_binop(op) => { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - if op.is_checkable() { - bug!("unexpected unchecked checkable binary operation"); - } else { - Ok(()) - } - } - Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) - if Self::check_binop(op) => - { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - self.checked_op_locals.insert(local); - Ok(()) - } - Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span); - Ok(()) - } - Rvalue::Cast(cast_kind, ref operand, ty) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = - self.add_node(Node::Cast(cast_kind, operand, ty), span); - Ok(()) - } - _ => self.error(Some(span), "unsupported rvalue")?, - } - } - // These are not actually relevant for us here, so we can ignore them. - StatementKind::AscribeUserType(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) => Ok(()), - _ => self.error(Some(stmt.source_info.span), "unsupported statement")?, - } - } - - /// Possible return values: - /// - /// - `None`: unsupported terminator, stop building - /// - `Some(None)`: supported terminator, finish building - /// - `Some(Some(block))`: support terminator, build `block` next - fn build_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> Result, ErrorReported> { - debug!("AbstractConstBuilder: terminator={:?}", terminator); - match terminator.kind { - TerminatorKind::Goto { target } => Ok(Some(target)), - TerminatorKind::Return => Ok(None), - TerminatorKind::Call { - ref func, - ref args, - destination: Some((ref place, target)), - // We do not care about `cleanup` here. Any branch which - // uses `cleanup` will fail const-eval and they therefore - // do not matter when checking for const evaluatability. - // - // Do note that even if `panic::catch_unwind` is made const, - // we still do not have to care about this, as we do not look - // into functions. - cleanup: _, - // Do not allow overloaded operators for now, - // we probably do want to allow this in the future. - // - // This is currently fairly irrelevant as it requires `const Trait`s. - from_hir_call: true, - fn_span, - } => { - let local = self.place_to_local(fn_span, place)?; - let func = self.operand_to_node(fn_span, func)?; - let args = self.tcx.arena.alloc_from_iter( - args.iter() - .map(|arg| self.operand_to_node(terminator.source_info.span, arg)) - .collect::, _>>()?, - ); - self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span); - Ok(Some(target)) - } - TerminatorKind::Assert { ref cond, expected: false, target, .. } => { - let p = match cond { - mir::Operand::Copy(p) | mir::Operand::Move(p) => p, - mir::Operand::Constant(_) => bug!("unexpected assert"), - }; - - const ONE_FIELD: mir::Field = mir::Field::from_usize(1); - debug!("proj: {:?}", p.projection); - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - // Mark locals directly used in asserts as used. - // - // This is needed because division does not use `CheckedBinop` but instead - // adds an explicit assert for `divisor != 0`. - self.nodes[self.locals[p]].used = true; - return Ok(Some(target)); - } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { - // Only allow asserts checking the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - return Ok(Some(target)); - } - } - - self.error(Some(terminator.source_info.span), "unsupported assertion")?; - } - _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?, - } - } - - /// Builds the abstract const by walking the mir from start to finish - /// and bailing out when encountering an unsupported operation. + /// Builds the abstract const by walking the thir and bailing out when + /// encountering an unspported operation. fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { - let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; - // We checked for a cyclic cfg above, so this should terminate. - loop { - debug!("AbstractConstBuilder: block={:?}", block); - for stmt in block.statements.iter() { - self.build_statement(stmt)?; - } - - if let Some(next) = self.build_terminator(block.terminator())? { - block = &self.body.basic_blocks()[next]; - } else { - break; - } - } + debug!("Abstractconstbuilder::build: body={:?}", &*self.body); + let last = self.recurse_build(self.body_id)?; + self.nodes[last].used = true; - assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap()); for n in self.nodes.iter() { if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node { // `AbstractConst`s should not contain any promoteds as they require references which @@ -523,13 +335,108 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - self.nodes[self.locals[mir::RETURN_PLACE]].used = true; if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { self.error(Some(unused.span), "dead code")?; } Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node))) } + + fn recurse_build(&mut self, node: thir::ExprId) -> Result { + use thir::ExprKind; + let node = &self.body.clone().exprs[node]; + debug!("recurse_build: node={:?}", node); + Ok(match &node.kind { + // I dont know if handling of these 3 is correct + &ExprKind::Scope { value, .. } => self.recurse_build(value)?, + &ExprKind::PlaceTypeAscription { source, .. } | + &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + + &ExprKind::Literal { literal, .. } + | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span), + + // FIXME(generic_const_exprs) handle `from_hir_call` field + ExprKind::Call { fun, args, .. } => { + let fun = self.recurse_build(*fun)?; + + let mut new_args = Vec::::with_capacity(args.len()); + for &id in args.iter() { + new_args.push(self.recurse_build(id)?); + } + let new_args = self.tcx.arena.alloc_slice(&new_args); + self.add_node(Node::FunctionCall(fun, new_args), node.span) + }, + &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { + let lhs = self.recurse_build(lhs)?; + let rhs = self.recurse_build(rhs)?; + self.add_node(Node::Binop(op, lhs, rhs), node.span) + } + &ExprKind::Unary { op, arg } if Self::check_unop(op) => { + let arg = self.recurse_build(arg)?; + self.add_node(Node::UnaryOp(op, arg), node.span) + }, + // HACK: without this arm the following doesn't compile: + // ``` + // fn foo(_: [(); N + 1]) { + // bar::<{ N + 1}>(); + // } + // ``` + // we ought to properly handle this in `try_unify` + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, + ExprKind::Block { body } => { + let mut stmts = Vec::with_capacity(body.stmts.len()); + for &id in body.stmts.iter() { + match &self.body.stmts[id].kind { + thir::StmtKind::Let { .. } => return self.error( + Some(node.span), + "let statements are not supported in generic constants", + ).map(|never| never), + thir::StmtKind::Expr { expr, .. } => stmts.push(self.recurse_build(*expr)?), + } + }; + let stmts = self.tcx.arena.alloc_slice(&stmts); + let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?; + self.add_node(Node::Block(stmts, opt_expr), node.span) + } + &ExprKind::Cast { source } => todo!(), + // never can arise even without panic/fail to terminate + &ExprKind::NeverToAny { source } => todo!(), + // i think this is a dummy usage of the expr to allow coercions + &ExprKind::Use { source } => todo!(), + + ExprKind::Return { .. } + | ExprKind::Box { .. } // allocations not allowed in constants + | ExprKind::AssignOp { .. } + | ExprKind::AddressOf { .. } // FIXME(generic_const_exprs) + | ExprKind::Borrow { .. } // FIXME(generic_const_exprs) + | ExprKind::Deref { .. } // FIXME(generic_const_exprs) + | ExprKind::Repeat { .. } // FIXME(generic_const_exprs) + | ExprKind::Array { .. } // FIXME(generic_const_exprs) + | ExprKind::Tuple { .. } // FIXME(generic_const_exprs) + | ExprKind::Index { .. } // FIXME(generic_const_exprs) + | ExprKind::Field { .. } // FIXME(generic_const_exprs) + | ExprKind::ConstBlock { .. } // FIXME(generic_const_exprs) + | ExprKind::Adt(_) // FIXME(generic_const_exprs) we *should* permit this but dont currently + | ExprKind::Match { .. } + | ExprKind::VarRef { .. } // + | ExprKind::UpvarRef { .. } // we dont permit let stmts so... + | ExprKind::Closure { .. } + | ExprKind::Let { .. } // let expressions imply control flow + | ExprKind::Loop { .. } + | ExprKind::Assign { .. } + | ExprKind::LogicalOp { .. } + | ExprKind::Unary { .. } // + | ExprKind::Binary { .. } // we handle valid unary/binary ops above + | ExprKind::Break { .. } + | ExprKind::Continue { .. } + | ExprKind::If { .. } + | ExprKind::Pointer { .. } // dont know if this is correct + | ExprKind::ThreadLocalRef(_) + | ExprKind::LlvmInlineAsm { .. } + | ExprKind::InlineAsm { .. } + | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never), + }) + } } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. @@ -547,8 +454,17 @@ pub(super) fn mir_abstract_const<'tcx>( DefKind::AnonConst => (), _ => return Ok(None), } - let body = tcx.mir_const(def).borrow(); - AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose() + debug!("mir_abstract_const: {:?}", def); + let body = tcx.thir_body(def); + + if body.0.borrow().exprs.is_empty() { + // type error in constant, there is no thir + return Err(ErrorReported); + } + + AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))? + .map(AbstractConstBuilder::build) + .transpose() } else { Ok(None) } @@ -599,6 +515,12 @@ where recurse(tcx, ct.subtree(func), f)?; args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } + Node::Block(stmts, opt_expr) => { + for id in stmts.iter().copied().chain(opt_expr) { + recurse(tcx, ct.subtree(id), f)?; + } + ControlFlow::CONTINUE + } Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 57b8a84300ff9..e64cc9e4b8f28 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -844,9 +844,10 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( self.visit_const(leaf) } Node::Cast(_, _, ty) => self.visit_ty(ty), - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } + Node::Block(_, _) + | Node::Binop(..) + | Node::UnaryOp(..) + | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }) } else { ControlFlow::CONTINUE From 9b2913814b95e1b8f123da59ddecb1bc6b3813af Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 16:14:01 +0100 Subject: [PATCH 06/32] as casts and block exprs --- .../rustc_middle/src/mir/abstract_const.rs | 4 +- compiler/rustc_privacy/src/lib.rs | 2 +- .../src/traits/const_evaluatable.rs | 84 ++++++++++++------- .../src/traits/object_safety.rs | 2 +- 4 files changed, 57 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index e75f084e79e21..1158a9f4f8008 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -1,5 +1,5 @@ //! A subset of a mir body used for const evaluatability checking. -use crate::mir::{self, CastKind}; +use crate::mir; use crate::ty::{self, Ty}; rustc_index::newtype_index! { @@ -18,7 +18,7 @@ pub enum Node<'tcx> { UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), Block(&'tcx [NodeId], Option), - Cast(CastKind, NodeId, Ty<'tcx>), + Cast(NodeId, Ty<'tcx>), } #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 26e1c3e7b8cf4..7d0f6767900a3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -158,7 +158,7 @@ where let leaf = leaf.subst(tcx, ct.substs); self.visit_const(leaf) } - ACNode::Cast(_, _, ty) => self.visit_ty(ty), + ACNode::Cast(_, ty) => self.visit_ty(ty), ACNode::Block(_, _) | ACNode::Binop(..) | ACNode::UnaryOp(..) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4e11fefdc81f3..461ebba58d985 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -92,7 +92,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Cast(_, _, ty) => { + Node::Cast(_, ty) => { let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; @@ -292,7 +292,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { stmts.iter().for_each(|&id| self.nodes[id].used = true); opt_expr.map(|e| self.nodes[e].used = true); } - Node::Cast(_, operand, _) => { + Node::Cast(operand, _) => { self.nodes[operand].used = true; } } @@ -335,6 +335,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + // FIXME I dont even think we can get unused nodes anymore with thir abstract const if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { self.error(Some(unused.span), "dead code")?; } @@ -352,6 +353,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::PlaceTypeAscription { source, .. } | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + // subtle: associated consts are literals this arm handles + // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span), @@ -375,14 +378,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(arg)?; self.add_node(Node::UnaryOp(op, arg), node.span) }, - // HACK: without this arm the following doesn't compile: - // ``` - // fn foo(_: [(); N + 1]) { - // bar::<{ N + 1}>(); - // } - // ``` - // we ought to properly handle this in `try_unify` - ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, ExprKind::Block { body } => { let mut stmts = Vec::with_capacity(body.stmts.len()); for &id in body.stmts.iter() { @@ -398,26 +393,34 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?; self.add_node(Node::Block(stmts, opt_expr), node.span) } - &ExprKind::Cast { source } => todo!(), + + // ExprKind::Use happens when a `hir::ExprKind::Cast` is a + // "coercion cast" i.e. using a coercion or is a no-op. + // this is important so that `N as usize as usize` doesnt unify with `N as usize` + &ExprKind::Use { source} + | &ExprKind::Cast { source } => { + let arg = self.recurse_build(source)?; + self.add_node(Node::Cast(arg, node.ty), node.span) + }, // never can arise even without panic/fail to terminate &ExprKind::NeverToAny { source } => todo!(), - // i think this is a dummy usage of the expr to allow coercions - &ExprKind::Use { source } => todo!(), - ExprKind::Return { .. } - | ExprKind::Box { .. } // allocations not allowed in constants - | ExprKind::AssignOp { .. } - | ExprKind::AddressOf { .. } // FIXME(generic_const_exprs) - | ExprKind::Borrow { .. } // FIXME(generic_const_exprs) - | ExprKind::Deref { .. } // FIXME(generic_const_exprs) - | ExprKind::Repeat { .. } // FIXME(generic_const_exprs) - | ExprKind::Array { .. } // FIXME(generic_const_exprs) - | ExprKind::Tuple { .. } // FIXME(generic_const_exprs) - | ExprKind::Index { .. } // FIXME(generic_const_exprs) - | ExprKind::Field { .. } // FIXME(generic_const_exprs) - | ExprKind::ConstBlock { .. } // FIXME(generic_const_exprs) - | ExprKind::Adt(_) // FIXME(generic_const_exprs) we *should* permit this but dont currently - | ExprKind::Match { .. } + // FIXME(generic_const_exprs) we want to support these + ExprKind::AddressOf { .. } + | ExprKind::Borrow { .. } + | ExprKind::Deref { .. } + | ExprKind::Repeat { .. } + | ExprKind::Array { .. } + | ExprKind::Tuple { .. } + | ExprKind::Index { .. } + | ExprKind::Field { .. } + | ExprKind::ConstBlock { .. } + | ExprKind::Adt(_) => return self.error( + Some(node.span), + "unsupported operation in generic constant, this may be supported in the future", + ).map(|never| never), + + ExprKind::Match { .. } | ExprKind::VarRef { .. } // | ExprKind::UpvarRef { .. } // we dont permit let stmts so... | ExprKind::Closure { .. } @@ -433,6 +436,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Pointer { .. } // dont know if this is correct | ExprKind::ThreadLocalRef(_) | ExprKind::LlvmInlineAsm { .. } + | ExprKind::Return { .. } + | ExprKind::Box { .. } // allocations not allowed in constants + | ExprKind::AssignOp { .. } | ExprKind::InlineAsm { .. } | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never), }) @@ -521,7 +527,7 @@ where } ControlFlow::CONTINUE } - Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), + Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f), } } @@ -604,11 +610,27 @@ pub(super) fn try_unify<'tcx>( && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } - (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty)) - if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) => + (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty)) + if (a_ty == b_ty) => { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } - _ => false, + (Node::Block(a_stmts, a_opt_expr), Node::Block(b_stmts, b_opt_expr)) + if a_stmts.len() == b_stmts.len() => { + a_stmts.iter().zip(b_stmts.iter()).all(|(&a_stmt, &b_stmt)| { + try_unify(tcx, a.subtree(a_stmt), b.subtree(b_stmt)) + }) && match (a_opt_expr, b_opt_expr) { + (Some(a_expr), Some(b_expr)) => try_unify(tcx, a.subtree(a_expr), b.subtree(b_expr)), + (None, None) => true, + _ => false, + } + } + // use this over `_ => false` to make adding variants to `Node` less error prone + (Node::Block(..), _) + | (Node::Cast(..), _) + | (Node::FunctionCall(..), _) + | (Node::UnaryOp(..), _) + | (Node::Binop(..), _) + | (Node::Leaf(..), _) => false, } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index e64cc9e4b8f28..3527aede609a4 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -843,7 +843,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } - Node::Cast(_, _, ty) => self.visit_ty(ty), + Node::Cast(_, ty) => self.visit_ty(ty), Node::Block(_, _) | Node::Binop(..) | Node::UnaryOp(..) From 4483c2bdf64e213627998ac7e2340de7dafb3037 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 18:20:09 +0100 Subject: [PATCH 07/32] dont support blocks --- .../rustc_middle/src/mir/abstract_const.rs | 1 - compiler/rustc_privacy/src/lib.rs | 3 +- .../src/traits/const_evaluatable.rs | 51 ++++--------------- .../src/traits/object_safety.rs | 3 +- .../generic_const_exprs/unused_expr.stderr | 12 ++--- 5 files changed, 16 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index 1158a9f4f8008..27849e4bdb0bf 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -17,7 +17,6 @@ pub enum Node<'tcx> { Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), - Block(&'tcx [NodeId], Option), Cast(NodeId, Ty<'tcx>), } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 7d0f6767900a3..02ea34ea9743f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,8 +159,7 @@ where self.visit_const(leaf) } ACNode::Cast(_, ty) => self.visit_ty(ty), - ACNode::Block(_, _) - | ACNode::Binop(..) + ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => ControlFlow::CONTINUE, }) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 461ebba58d985..77fe1f514d901 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -102,8 +102,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Block(_, _) - | Node::Binop(_, _, _) + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }); @@ -288,10 +287,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes[func].used = true; nodes.iter().for_each(|&n| self.nodes[n].used = true); } - Node::Block(stmts, opt_expr) => { - stmts.iter().for_each(|&id| self.nodes[id].used = true); - opt_expr.map(|e| self.nodes[e].used = true); - } Node::Cast(operand, _) => { self.nodes[operand].used = true; } @@ -378,22 +373,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(arg)?; self.add_node(Node::UnaryOp(op, arg), node.span) }, - ExprKind::Block { body } => { - let mut stmts = Vec::with_capacity(body.stmts.len()); - for &id in body.stmts.iter() { - match &self.body.stmts[id].kind { - thir::StmtKind::Let { .. } => return self.error( - Some(node.span), - "let statements are not supported in generic constants", - ).map(|never| never), - thir::StmtKind::Expr { expr, .. } => stmts.push(self.recurse_build(*expr)?), - } - }; - let stmts = self.tcx.arena.alloc_slice(&stmts); - let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?; - self.add_node(Node::Block(stmts, opt_expr), node.span) - } - + // this is necessary so that the following compiles: + // + // ``` + // fn foo(a: [(); N + 1]) { + // bar::<{ N + 1 }>(); + // } + // ``` + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, // ExprKind::Use happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. // this is important so that `N as usize as usize` doesnt unify with `N as usize` @@ -411,6 +398,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Deref { .. } | ExprKind::Repeat { .. } | ExprKind::Array { .. } + | ExprKind::Block { .. } | ExprKind::Tuple { .. } | ExprKind::Index { .. } | ExprKind::Field { .. } @@ -521,12 +509,6 @@ where recurse(tcx, ct.subtree(func), f)?; args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } - Node::Block(stmts, opt_expr) => { - for id in stmts.iter().copied().chain(opt_expr) { - recurse(tcx, ct.subtree(id), f)?; - } - ControlFlow::CONTINUE - } Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f), } } @@ -615,19 +597,8 @@ pub(super) fn try_unify<'tcx>( { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } - (Node::Block(a_stmts, a_opt_expr), Node::Block(b_stmts, b_opt_expr)) - if a_stmts.len() == b_stmts.len() => { - a_stmts.iter().zip(b_stmts.iter()).all(|(&a_stmt, &b_stmt)| { - try_unify(tcx, a.subtree(a_stmt), b.subtree(b_stmt)) - }) && match (a_opt_expr, b_opt_expr) { - (Some(a_expr), Some(b_expr)) => try_unify(tcx, a.subtree(a_expr), b.subtree(b_expr)), - (None, None) => true, - _ => false, - } - } // use this over `_ => false` to make adding variants to `Node` less error prone - (Node::Block(..), _) - | (Node::Cast(..), _) + (Node::Cast(..), _) | (Node::FunctionCall(..), _) | (Node::UnaryOp(..), _) | (Node::Binop(..), _) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 3527aede609a4..d9ea259155358 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -844,8 +844,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( self.visit_const(leaf) } Node::Cast(_, ty) => self.visit_ty(ty), - Node::Block(_, _) - | Node::Binop(..) + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }) diff --git a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr index 1687dbbcbe3f8..3da91b19a5ed9 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr @@ -2,9 +2,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:4:34 | LL | fn add() -> [u8; { N + 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -12,9 +10,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:9:34 | LL | fn div() -> [u8; { N / 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -22,9 +18,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:16:38 | LL | fn fn_call() -> [u8; { foo(N); 5 }] { - | ^^------^^^^^ - | | - | dead code + | ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function From 47b16f4ac9145538e8375d2625181df281206be7 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 18:41:05 +0100 Subject: [PATCH 08/32] bless stderr --- .../array-size-in-generic-struct-param.full.stderr | 2 +- .../ui/const-generics/generic_const_exprs/closures.stderr | 2 +- .../generic_const_exprs/let-bindings.stderr | 8 ++------ src/test/ui/const-generics/issues/issue-67375.full.stderr | 6 +++--- .../ui/const-generics/issues/issue-67945-2.full.stderr | 3 +-- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr index deb6f3bd12c1d..9b3c32a939779 100644 --- a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr @@ -10,7 +10,7 @@ error: overly complex generic constant --> $DIR/array-size-in-generic-struct-param.rs:19:15 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^ unsupported projection + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr index 9f0b7252e8326..95dae4ecc0431 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr @@ -4,7 +4,7 @@ error: overly complex generic constant LL | fn test() -> [u8; N + (|| 42)()] {} | ^^^^-------^^ | | - | unsupported rvalue + | unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr index 5749defb3e12c..c9f847995223a 100644 --- a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr @@ -2,9 +2,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -12,9 +10,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr index 5386ef56a245a..d7b52063dc4db 100644 --- a/src/test/ui/const-generics/issues/issue-67375.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr @@ -2,9 +2,9 @@ error: overly complex generic constant --> $DIR/issue-67375.rs:7:17 | LL | inner: [(); { [|_: &T| {}; 0].len() }], - | ^^^----------^^^^^^^^^^^^ - | | - | unsupported rvalue + | ^^---------------^^^^^^^^ + | | + | unsupported operation in generic constant | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr index 118cf447c01e2..fe0351a829220 100644 --- a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr @@ -5,11 +5,10 @@ LL | A: [(); { | _____________^ LL | | LL | | let x: Option> = None; - | | ---- unsupported rvalue LL | | LL | | 0 LL | | }], - | |_____^ + | |_____^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function From c170dcf04c62ffd79cbf28f340aaf6824e70f493 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 23:18:25 +0100 Subject: [PATCH 09/32] tidy --- compiler/rustc_privacy/src/lib.rs | 6 ++-- .../src/traits/const_evaluatable.rs | 30 +++++++++---------- .../src/traits/object_safety.rs | 6 ++-- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 02ea34ea9743f..910249ecc479e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,9 +159,9 @@ where self.visit_const(leaf) } ACNode::Cast(_, ty) => self.visit_ty(ty), - ACNode::Binop(..) - | ACNode::UnaryOp(..) - | ACNode::FunctionCall(_, _) => ControlFlow::CONTINUE, + ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }) } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 77fe1f514d901..7d69ec54bdf02 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -102,9 +102,9 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Binop(_, _, _) - | Node::UnaryOp(_, _) - | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }); match failure_kind { @@ -348,8 +348,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::PlaceTypeAscription { source, .. } | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, - // subtle: associated consts are literals this arm handles - // `::ASSOC` as well as `12` + // subtle: associated consts are literals this arm handles + // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span), @@ -381,10 +381,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // } // ``` ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, - // ExprKind::Use happens when a `hir::ExprKind::Cast` is a + // ExprKind::Use happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. // this is important so that `N as usize as usize` doesnt unify with `N as usize` - &ExprKind::Use { source} + &ExprKind::Use { source} | &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; self.add_node(Node::Cast(arg, node.ty), node.span) @@ -404,7 +404,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Field { .. } | ExprKind::ConstBlock { .. } | ExprKind::Adt(_) => return self.error( - Some(node.span), + Some(node.span), "unsupported operation in generic constant, this may be supported in the future", ).map(|never| never), @@ -417,7 +417,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Assign { .. } | ExprKind::LogicalOp { .. } | ExprKind::Unary { .. } // - | ExprKind::Binary { .. } // we handle valid unary/binary ops above + | ExprKind::Binary { .. } // we handle valid unary/binary ops above | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::If { .. } @@ -592,16 +592,14 @@ pub(super) fn try_unify<'tcx>( && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } - (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty)) - if (a_ty == b_ty) => - { + (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty)) if (a_ty == b_ty) => { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } // use this over `_ => false` to make adding variants to `Node` less error prone - (Node::Cast(..), _) - | (Node::FunctionCall(..), _) - | (Node::UnaryOp(..), _) - | (Node::Binop(..), _) + (Node::Cast(..), _) + | (Node::FunctionCall(..), _) + | (Node::UnaryOp(..), _) + | (Node::Binop(..), _) | (Node::Leaf(..), _) => false, } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index d9ea259155358..63bd10994b1ac 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -844,9 +844,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( self.visit_const(leaf) } Node::Cast(_, ty) => self.visit_ty(ty), - Node::Binop(..) - | Node::UnaryOp(..) - | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }) } else { ControlFlow::CONTINUE From 08e86440165619c57e0072eb742c7dad3cfd0950 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:05:24 +0100 Subject: [PATCH 10/32] move thir visitor to rustc_middle --- compiler/rustc_middle/src/thir.rs | 243 ++++++++++++++++++ .../rustc_mir_build/src/check_unsafety.rs | 2 +- compiler/rustc_mir_build/src/thir/mod.rs | 1 - compiler/rustc_mir_build/src/thir/visit.rs | 240 ----------------- 4 files changed, 244 insertions(+), 242 deletions(-) delete mode 100644 compiler/rustc_mir_build/src/thir/visit.rs diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 91a64e163e7c0..3012676c872bd 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -818,3 +818,246 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } } } + +pub mod visit { + use super::*; + pub trait Visitor<'a, 'tcx: 'a>: Sized { + fn thir(&self) -> &'a Thir<'tcx>; + + fn visit_expr(&mut self, expr: &Expr<'tcx>) { + walk_expr(self, expr); + } + + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { + walk_stmt(self, stmt); + } + + fn visit_block(&mut self, block: &Block) { + walk_block(self, block); + } + + fn visit_arm(&mut self, arm: &Arm<'tcx>) { + walk_arm(self, arm); + } + + fn visit_pat(&mut self, pat: &Pat<'tcx>) { + walk_pat(self, pat); + } + + fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} + } + + pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { + use ExprKind::*; + match expr.kind { + Scope { value, region_scope: _, lint_level: _ } => { + visitor.visit_expr(&visitor.thir()[value]) + } + Box { value } => visitor.visit_expr(&visitor.thir()[value]), + If { cond, then, else_opt, if_then_scope: _ } => { + visitor.visit_expr(&visitor.thir()[cond]); + visitor.visit_expr(&visitor.thir()[then]); + if let Some(else_expr) = else_opt { + visitor.visit_expr(&visitor.thir()[else_expr]); + } + } + Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { + visitor.visit_expr(&visitor.thir()[fun]); + for &arg in &**args { + visitor.visit_expr(&visitor.thir()[arg]); + } + } + Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), + Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Cast { source } => visitor.visit_expr(&visitor.thir()[source]), + Use { source } => visitor.visit_expr(&visitor.thir()[source]), + NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), + Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + Let { expr, .. } => { + visitor.visit_expr(&visitor.thir()[expr]); + } + Loop { body } => visitor.visit_expr(&visitor.thir()[body]), + Match { scrutinee, ref arms } => { + visitor.visit_expr(&visitor.thir()[scrutinee]); + for &arm in &**arms { + visitor.visit_arm(&visitor.thir()[arm]); + } + } + Block { ref body } => visitor.visit_block(body), + Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), + Index { lhs, index } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[index]); + } + VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} + Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), + AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Break { value, label: _ } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + Continue { label: _ } => {} + Return { value } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + ConstBlock { value } => visitor.visit_const(value), + Repeat { value, count } => { + visitor.visit_expr(&visitor.thir()[value]); + visitor.visit_const(count); + } + Array { ref fields } | Tuple { ref fields } => { + for &field in &**fields { + visitor.visit_expr(&visitor.thir()[field]); + } + } + Adt(box crate::thir::Adt { + ref fields, + ref base, + adt_def: _, + variant_index: _, + substs: _, + user_ty: _, + }) => { + for field in &**fields { + visitor.visit_expr(&visitor.thir()[field.expr]); + } + if let Some(base) = base { + visitor.visit_expr(&visitor.thir()[base.base]); + } + } + PlaceTypeAscription { source, user_ty: _ } + | ValueTypeAscription { source, user_ty: _ } => { + visitor.visit_expr(&visitor.thir()[source]) + } + Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} + Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), + StaticRef { literal, def_id: _ } => visitor.visit_const(literal), + InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + for op in &**operands { + use InlineAsmOperand::*; + match op { + In { expr, reg: _ } + | Out { expr: Some(expr), reg: _, late: _ } + | InOut { expr, reg: _, late: _ } + | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), + SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + visitor.visit_expr(&visitor.thir()[*in_expr]); + if let Some(out_expr) = out_expr { + visitor.visit_expr(&visitor.thir()[*out_expr]); + } + } + Out { expr: None, reg: _, late: _ } + | Const { value: _, span: _ } + | SymStatic { def_id: _ } => {} + } + } + } + ThreadLocalRef(_) => {} + LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { + for &out_expr in &**outputs { + visitor.visit_expr(&visitor.thir()[out_expr]); + } + for &in_expr in &**inputs { + visitor.visit_expr(&visitor.thir()[in_expr]); + } + } + Yield { value } => visitor.visit_expr(&visitor.thir()[value]), + } + } + + pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { + match &stmt.kind { + StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), + StmtKind::Let { + initializer, + remainder_scope: _, + init_scope: _, + ref pattern, + lint_level: _, + } => { + if let Some(init) = initializer { + visitor.visit_expr(&visitor.thir()[*init]); + } + visitor.visit_pat(pattern); + } + } + } + + pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { + for &stmt in &*block.stmts { + visitor.visit_stmt(&visitor.thir()[stmt]); + } + if let Some(expr) = block.expr { + visitor.visit_expr(&visitor.thir()[expr]); + } + } + + pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { + match arm.guard { + Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), + Some(Guard::IfLet(ref pat, expr)) => { + visitor.visit_pat(pat); + visitor.visit_expr(&visitor.thir()[expr]); + } + None => {} + } + visitor.visit_pat(&arm.pattern); + visitor.visit_expr(&visitor.thir()[arm.body]); + } + + pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { + use PatKind::*; + match pat.kind.as_ref() { + AscribeUserType { subpattern, ascription: _ } + | Deref { subpattern } + | Binding { + subpattern: Some(subpattern), + mutability: _, + mode: _, + var: _, + ty: _, + is_primary: _, + name: _, + } => visitor.visit_pat(&subpattern), + Binding { .. } | Wild => {} + Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } + | Leaf { subpatterns } => { + for subpattern in subpatterns { + visitor.visit_pat(&subpattern.pattern); + } + } + Constant { value } => visitor.visit_const(value), + Range(range) => { + visitor.visit_const(range.lo); + visitor.visit_const(range.hi); + } + Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { + for subpattern in prefix { + visitor.visit_pat(&subpattern); + } + if let Some(pat) = slice { + visitor.visit_pat(pat); + } + for subpattern in suffix { + visitor.visit_pat(&subpattern); + } + } + Or { pats } => { + for pat in pats { + visitor.visit_pat(&pat); + } + } + }; + } +} diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 05a5fcef16ae5..0e82b18720142 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,5 +1,5 @@ use crate::build::ExprCategory; -use crate::thir::visit::{self, Visitor}; +use rustc_middle::thir::visit::{self, Visitor}; use rustc_errors::struct_span_err; use rustc_hir as hir; diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index e5123d8ef0c99..ddbe1b0b69c1e 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -11,4 +11,3 @@ crate mod cx; crate mod pattern; mod util; -pub mod visit; diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs deleted file mode 100644 index 51c371b872057..0000000000000 --- a/compiler/rustc_mir_build/src/thir/visit.rs +++ /dev/null @@ -1,240 +0,0 @@ -use rustc_middle::thir::{self, *}; -use rustc_middle::ty::Const; - -pub trait Visitor<'a, 'tcx: 'a>: Sized { - fn thir(&self) -> &'a Thir<'tcx>; - - fn visit_expr(&mut self, expr: &Expr<'tcx>) { - walk_expr(self, expr); - } - - fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { - walk_stmt(self, stmt); - } - - fn visit_block(&mut self, block: &Block) { - walk_block(self, block); - } - - fn visit_arm(&mut self, arm: &Arm<'tcx>) { - walk_arm(self, arm); - } - - fn visit_pat(&mut self, pat: &Pat<'tcx>) { - walk_pat(self, pat); - } - - fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} -} - -pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { - use ExprKind::*; - match expr.kind { - Scope { value, region_scope: _, lint_level: _ } => { - visitor.visit_expr(&visitor.thir()[value]) - } - Box { value } => visitor.visit_expr(&visitor.thir()[value]), - If { cond, then, else_opt, if_then_scope: _ } => { - visitor.visit_expr(&visitor.thir()[cond]); - visitor.visit_expr(&visitor.thir()[then]); - if let Some(else_expr) = else_opt { - visitor.visit_expr(&visitor.thir()[else_expr]); - } - } - Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { - visitor.visit_expr(&visitor.thir()[fun]); - for &arg in &**args { - visitor.visit_expr(&visitor.thir()[arg]); - } - } - Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), - Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Cast { source } => visitor.visit_expr(&visitor.thir()[source]), - Use { source } => visitor.visit_expr(&visitor.thir()[source]), - NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), - Let { expr, .. } => { - visitor.visit_expr(&visitor.thir()[expr]); - } - Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - Match { scrutinee, ref arms } => { - visitor.visit_expr(&visitor.thir()[scrutinee]); - for &arm in &**arms { - visitor.visit_arm(&visitor.thir()[arm]); - } - } - Block { ref body } => visitor.visit_block(body), - Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), - Index { lhs, index } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[index]); - } - VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} - Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), - AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Break { value, label: _ } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - Continue { label: _ } => {} - Return { value } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - ConstBlock { value } => visitor.visit_const(value), - Repeat { value, count } => { - visitor.visit_expr(&visitor.thir()[value]); - visitor.visit_const(count); - } - Array { ref fields } | Tuple { ref fields } => { - for &field in &**fields { - visitor.visit_expr(&visitor.thir()[field]); - } - } - Adt(box thir::Adt { - ref fields, - ref base, - adt_def: _, - variant_index: _, - substs: _, - user_ty: _, - }) => { - for field in &**fields { - visitor.visit_expr(&visitor.thir()[field.expr]); - } - if let Some(base) = base { - visitor.visit_expr(&visitor.thir()[base.base]); - } - } - PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { - visitor.visit_expr(&visitor.thir()[source]) - } - Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} - Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), - StaticRef { literal, def_id: _ } => visitor.visit_const(literal), - InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { - for op in &**operands { - use InlineAsmOperand::*; - match op { - In { expr, reg: _ } - | Out { expr: Some(expr), reg: _, late: _ } - | InOut { expr, reg: _, late: _ } - | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), - SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - visitor.visit_expr(&visitor.thir()[*in_expr]); - if let Some(out_expr) = out_expr { - visitor.visit_expr(&visitor.thir()[*out_expr]); - } - } - Out { expr: None, reg: _, late: _ } - | Const { value: _, span: _ } - | SymStatic { def_id: _ } => {} - } - } - } - ThreadLocalRef(_) => {} - LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { - for &out_expr in &**outputs { - visitor.visit_expr(&visitor.thir()[out_expr]); - } - for &in_expr in &**inputs { - visitor.visit_expr(&visitor.thir()[in_expr]); - } - } - Yield { value } => visitor.visit_expr(&visitor.thir()[value]), - } -} - -pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { - match &stmt.kind { - StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), - StmtKind::Let { - initializer, - remainder_scope: _, - init_scope: _, - ref pattern, - lint_level: _, - } => { - if let Some(init) = initializer { - visitor.visit_expr(&visitor.thir()[*init]); - } - visitor.visit_pat(pattern); - } - } -} - -pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { - for &stmt in &*block.stmts { - visitor.visit_stmt(&visitor.thir()[stmt]); - } - if let Some(expr) = block.expr { - visitor.visit_expr(&visitor.thir()[expr]); - } -} - -pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { - match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), - Some(Guard::IfLet(ref pat, expr)) => { - visitor.visit_pat(pat); - visitor.visit_expr(&visitor.thir()[expr]); - } - None => {} - } - visitor.visit_pat(&arm.pattern); - visitor.visit_expr(&visitor.thir()[arm.body]); -} - -pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { - use PatKind::*; - match pat.kind.as_ref() { - AscribeUserType { subpattern, ascription: _ } - | Deref { subpattern } - | Binding { - subpattern: Some(subpattern), - mutability: _, - mode: _, - var: _, - ty: _, - is_primary: _, - name: _, - } => visitor.visit_pat(&subpattern), - Binding { .. } | Wild => {} - Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => { - for subpattern in subpatterns { - visitor.visit_pat(&subpattern.pattern); - } - } - Constant { value } => visitor.visit_const(value), - Range(range) => { - visitor.visit_const(range.lo); - visitor.visit_const(range.hi); - } - Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { - for subpattern in prefix { - visitor.visit_pat(&subpattern); - } - if let Some(pat) = slice { - visitor.visit_pat(pat); - } - for subpattern in suffix { - visitor.visit_pat(&subpattern); - } - } - Or { pats } => { - for pat in pats { - visitor.visit_pat(&pat); - } - } - }; -} From fc63e9a8fb619ad79d2d24db06078652a2a6c1ba Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:05:59 +0100 Subject: [PATCH 11/32] dont build abstract const for monomorphic consts --- .../src/traits/const_evaluatable.rs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 7d69ec54bdf02..3e1719e08acfa 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -267,7 +267,36 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let builder = AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() }; - // FIXME non-constants should return Ok(None) + struct IsThirPolymorphic<'a, 'tcx> { + is_poly: bool, + thir: &'a thir::Thir<'tcx>, + tcx: TyCtxt<'tcx>, + } + + use thir::visit; + impl<'a, 'tcx: 'a> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { + fn thir(&self) -> &'a thir::Thir<'tcx> { + &self.thir + } + + fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { + self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); + if self.is_poly { + return; + } + visit::walk_expr(self, expr); + } + + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { + self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx); + } + } + + let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; + visit::walk_expr(&mut is_poly_vis, &body[body_id]); + if is_poly_vis.is_poly == false { + return Ok(None); + } Ok(Some(builder)) } From 4cbcb0936a3ae16a99f977427a6a01646a1ed8dd Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:06:44 +0100 Subject: [PATCH 12/32] handle `ExprKind::NeverToAny` --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 3e1719e08acfa..21423d415e3b9 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -418,8 +418,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(source)?; self.add_node(Node::Cast(arg, node.ty), node.span) }, - // never can arise even without panic/fail to terminate - &ExprKind::NeverToAny { source } => todo!(), // FIXME(generic_const_exprs) we want to support these ExprKind::AddressOf { .. } @@ -428,6 +426,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Repeat { .. } | ExprKind::Array { .. } | ExprKind::Block { .. } + | ExprKind::NeverToAny { .. } // I dont think we can get this without adt construction | ExprKind::Tuple { .. } | ExprKind::Index { .. } | ExprKind::Field { .. } From 1f57f8b9032fa0f83aa59f634ac72f1e63a1cfa2 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:44:24 +0100 Subject: [PATCH 13/32] remove `WorkNode` --- .../src/traits/const_evaluatable.rs | 61 +++---------------- 1 file changed, 10 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 21423d415e3b9..c47b0c31ca01c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -224,24 +224,13 @@ impl<'tcx> AbstractConst<'tcx> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct WorkNode<'tcx> { - node: Node<'tcx>, - span: Span, - used: bool, -} - struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, body_id: thir::ExprId, + /// `Lrc` is used to avoid borrowck difficulties in `recurse_build` body: Lrc<&'a thir::Thir<'tcx>>, /// The current WIP node tree. - /// - /// We require all nodes to be used in the final abstract const, - /// so we store this here. Note that we also consider nodes as used - /// if they are mentioned in an assert, so some used nodes are never - /// actually reachable by walking the [`AbstractConst`]. - nodes: IndexVec>, + nodes: IndexVec>, } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { @@ -301,30 +290,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Ok(Some(builder)) } - fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId { - // Mark used nodes. - match node { - Node::Leaf(_) => (), - Node::Binop(_, lhs, rhs) => { - self.nodes[lhs].used = true; - self.nodes[rhs].used = true; - } - Node::UnaryOp(_, input) => { - self.nodes[input].used = true; - } - Node::FunctionCall(func, nodes) => { - self.nodes[func].used = true; - nodes.iter().for_each(|&n| self.nodes[n].used = true); - } - Node::Cast(operand, _) => { - self.nodes[operand].used = true; - } - } - - // Nodes start as unused. - self.nodes.push(WorkNode { node, span, used: false }) - } - /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; @@ -348,23 +313,17 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { /// encountering an unspported operation. fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { debug!("Abstractconstbuilder::build: body={:?}", &*self.body); - let last = self.recurse_build(self.body_id)?; - self.nodes[last].used = true; + self.recurse_build(self.body_id)?; for n in self.nodes.iter() { - if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node { + if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n { // `AbstractConst`s should not contain any promoteds as they require references which // are not allowed. assert_eq!(ct.promoted, None); } } - // FIXME I dont even think we can get unused nodes anymore with thir abstract const - if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { - self.error(Some(unused.span), "dead code")?; - } - - Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node))) + Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter())) } fn recurse_build(&mut self, node: thir::ExprId) -> Result { @@ -380,7 +339,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // subtle: associated consts are literals this arm handles // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } - | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span), + | &ExprKind::StaticRef { literal, .. } => self.nodes.push(Node::Leaf(literal)), // FIXME(generic_const_exprs) handle `from_hir_call` field ExprKind::Call { fun, args, .. } => { @@ -391,16 +350,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { new_args.push(self.recurse_build(id)?); } let new_args = self.tcx.arena.alloc_slice(&new_args); - self.add_node(Node::FunctionCall(fun, new_args), node.span) + self.nodes.push(Node::FunctionCall(fun, new_args)) }, &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { let lhs = self.recurse_build(lhs)?; let rhs = self.recurse_build(rhs)?; - self.add_node(Node::Binop(op, lhs, rhs), node.span) + self.nodes.push(Node::Binop(op, lhs, rhs)) } &ExprKind::Unary { op, arg } if Self::check_unop(op) => { let arg = self.recurse_build(arg)?; - self.add_node(Node::UnaryOp(op, arg), node.span) + self.nodes.push(Node::UnaryOp(op, arg)) }, // this is necessary so that the following compiles: // @@ -416,7 +375,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::Use { source} | &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; - self.add_node(Node::Cast(arg, node.ty), node.span) + self.nodes.push(Node::Cast(arg, node.ty)) }, // FIXME(generic_const_exprs) we want to support these From 15101c8e95db6941f8c7d55fb301ad1b62748c7b Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 01:17:51 +0100 Subject: [PATCH 14/32] remove debug stmts --- compiler/rustc_mir_build/src/build/mod.rs | 2 -- compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 --- compiler/rustc_mir_build/src/thir/cx/mod.rs | 1 - compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 3 +-- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 390ce59cb489c..e931c686dde59 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -28,7 +28,6 @@ crate fn mir_built<'tcx>( if let Some(def) = def.try_upgrade(tcx) { return tcx.mir_built(def); } - debug!("mir_built: def={:?}", def); let mut body = mir_build(tcx, def); if def.const_param_did.is_some() { @@ -41,7 +40,6 @@ crate fn mir_built<'tcx>( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { - debug!("mir_build: def={:?}", def); let id = tcx.hir().local_def_id_to_hir_id(def.did); let body_owner_kind = tcx.hir().body_owner_kind(id); let typeck_results = tcx.typeck_opt_const_arg(def); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 70a5a9286b0b3..66005be05df75 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -149,9 +149,7 @@ impl<'tcx> Cx<'tcx> { } fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { - debug!("Expr::make_mirror_unadjusted: expr={:?}", expr); let expr_ty = self.typeck_results().expr_ty(expr); - debug!("Expr::make_mirror_unadjusted: expr_ty={:?}", expr_ty); let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let kind = match expr.kind { @@ -764,7 +762,6 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Err => unreachable!(), }; - debug!("Expr::make_mirror_unadjusted: finish"); Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5310efbccd655..5059dd939d92d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -20,7 +20,6 @@ crate fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: ty::WithOptConstParam, ) -> (&'tcx Steal>, ExprId) { - debug!("thir_body: {:?}", owner_def); let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did))); let mut cx = Cx::new(tcx, owner_def); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index c47b0c31ca01c..4251dc5e93904 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -435,9 +435,8 @@ pub(super) fn mir_abstract_const<'tcx>( DefKind::AnonConst => (), _ => return Ok(None), } - debug!("mir_abstract_const: {:?}", def); + let body = tcx.thir_body(def); - if body.0.borrow().exprs.is_empty() { // type error in constant, there is no thir return Err(ErrorReported); From 406d2ab95de0e90f45e00f6c1be1e4e7912aa153 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 01:56:29 +0100 Subject: [PATCH 15/32] rename mir -> thir around abstract consts --- compiler/rustc_metadata/src/rmeta/decoder.rs | 9 +- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 8 +- compiler/rustc_metadata/src/rmeta/mod.rs | 3 +- compiler/rustc_middle/src/mir/mod.rs | 1 - compiler/rustc_middle/src/mir/query.rs | 9 +- compiler/rustc_middle/src/query/mod.rs | 8 +- compiler/rustc_middle/src/thir.rs | 246 +----------------- .../src/{mir => thir}/abstract_const.rs | 0 compiler/rustc_middle/src/thir/visit.rs | 238 +++++++++++++++++ compiler/rustc_middle/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 5 +- compiler/rustc_mir_build/src/build/mod.rs | 4 +- compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_privacy/src/lib.rs | 2 +- .../rustc_query_impl/src/on_disk_cache.rs | 3 +- .../src/traits/const_evaluatable.rs | 12 +- .../src/traits/error_reporting/mod.rs | 2 +- .../src/traits/fulfill.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 10 +- .../src/traits/object_safety.rs | 2 +- .../src/traits/select/mod.rs | 2 +- 22 files changed, 287 insertions(+), 284 deletions(-) rename compiler/rustc_middle/src/{mir => thir}/abstract_const.rs (100%) create mode 100644 compiler/rustc_middle/src/thir/visit.rs diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index dd44e0cb1fa90..7ebea9ecc8ef2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -26,6 +26,7 @@ use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, Body, Promoted}; +use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; @@ -540,7 +541,7 @@ impl<'a, 'tcx> Decodable> for Span { } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { ty::codec::RefDecodable::decode(d) } @@ -1198,14 +1199,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_mir_abstract_const( + fn get_thir_abstract_const( &self, tcx: TyCtxt<'tcx>, id: DefIndex, - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { self.root .tables - .mir_abstract_consts + .thir_abstract_consts .get(self, id) .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 41839c58021ab..1a147242619a7 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -117,7 +117,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) } promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } - mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) } + thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d8b9a4799760e..60d7f0f85bb57 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -23,6 +23,7 @@ use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportLevel, }; use rustc_middle::mir::interpret; +use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; @@ -344,7 +345,7 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Encodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { (**self).encode(s) } @@ -1304,9 +1305,10 @@ impl EncodeContext<'a, 'tcx> { if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); - let abstract_const = self.tcx.mir_abstract_const(def_id); + // FIXME this feels wrong to have in `encode_mir` + let abstract_const = self.tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { - record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const); + record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const); } } record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a487753f4628a..e59e9ad5d15d6 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -15,6 +15,7 @@ use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; +use rustc_middle::thir; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; @@ -305,7 +306,7 @@ define_tables! { mir: Table)>, mir_for_ctfe: Table)>, promoted_mir: Table>)>, - mir_abstract_consts: Table])>, + thir_abstract_consts: Table])>, const_defaults: Table>>, unused_generic_params: Table>>, // `def_keys` and `def_path_hashes` represent a lazy version of a diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 38d4c5b4bd10e..ba8ccc71954ff 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -40,7 +40,6 @@ use self::graph_cyclic_cache::GraphIsCyclicCache; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; -pub mod abstract_const; pub mod coverage; mod generic_graph; pub mod generic_graphviz; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 1bdb6ca012b4a..a1c6a8bf99e79 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,6 +1,7 @@ //! Values computed by queries that use MIR. -use crate::mir::{abstract_const, Body, Promoted}; +use crate::mir::{Body, Promoted}; +use crate::thir::abstract_const; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; @@ -433,14 +434,14 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mir_abstract_const_opt_const_arg( + pub fn thir_abstract_const_opt_const_arg( self, def: ty::WithOptConstParam, ) -> Result]>, ErrorReported> { if let Some((did, param_did)) = def.as_const_arg() { - self.mir_abstract_const_of_const_arg((did, param_did)) + self.thir_abstract_const_of_const_arg((did, param_did)) } else { - self.mir_abstract_const(def.did) + self.thir_abstract_const(def.did) } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c93996162e3e3..19535195488b7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -295,17 +295,17 @@ rustc_queries! { } /// Try to build an abstract representation of the given constant. - query mir_abstract_const( + query thir_abstract_const( key: DefId - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } } /// Try to build an abstract representation of the given constant. - query mir_abstract_const_of_const_arg( + query thir_abstract_const_of_const_arg( key: (LocalDefId, DefId) - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for the const argument {}", diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3012676c872bd..8d6fd1e729d3b 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -33,6 +33,9 @@ use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; +pub mod abstract_const; +pub mod visit; + newtype_index! { /// An index to an [`Arm`] stored in [`Thir::arms`] #[derive(HashStable)] @@ -818,246 +821,3 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } } } - -pub mod visit { - use super::*; - pub trait Visitor<'a, 'tcx: 'a>: Sized { - fn thir(&self) -> &'a Thir<'tcx>; - - fn visit_expr(&mut self, expr: &Expr<'tcx>) { - walk_expr(self, expr); - } - - fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { - walk_stmt(self, stmt); - } - - fn visit_block(&mut self, block: &Block) { - walk_block(self, block); - } - - fn visit_arm(&mut self, arm: &Arm<'tcx>) { - walk_arm(self, arm); - } - - fn visit_pat(&mut self, pat: &Pat<'tcx>) { - walk_pat(self, pat); - } - - fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} - } - - pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { - use ExprKind::*; - match expr.kind { - Scope { value, region_scope: _, lint_level: _ } => { - visitor.visit_expr(&visitor.thir()[value]) - } - Box { value } => visitor.visit_expr(&visitor.thir()[value]), - If { cond, then, else_opt, if_then_scope: _ } => { - visitor.visit_expr(&visitor.thir()[cond]); - visitor.visit_expr(&visitor.thir()[then]); - if let Some(else_expr) = else_opt { - visitor.visit_expr(&visitor.thir()[else_expr]); - } - } - Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { - visitor.visit_expr(&visitor.thir()[fun]); - for &arg in &**args { - visitor.visit_expr(&visitor.thir()[arg]); - } - } - Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), - Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Cast { source } => visitor.visit_expr(&visitor.thir()[source]), - Use { source } => visitor.visit_expr(&visitor.thir()[source]), - NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), - Let { expr, .. } => { - visitor.visit_expr(&visitor.thir()[expr]); - } - Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - Match { scrutinee, ref arms } => { - visitor.visit_expr(&visitor.thir()[scrutinee]); - for &arm in &**arms { - visitor.visit_arm(&visitor.thir()[arm]); - } - } - Block { ref body } => visitor.visit_block(body), - Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), - Index { lhs, index } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[index]); - } - VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} - Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), - AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Break { value, label: _ } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - Continue { label: _ } => {} - Return { value } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - ConstBlock { value } => visitor.visit_const(value), - Repeat { value, count } => { - visitor.visit_expr(&visitor.thir()[value]); - visitor.visit_const(count); - } - Array { ref fields } | Tuple { ref fields } => { - for &field in &**fields { - visitor.visit_expr(&visitor.thir()[field]); - } - } - Adt(box crate::thir::Adt { - ref fields, - ref base, - adt_def: _, - variant_index: _, - substs: _, - user_ty: _, - }) => { - for field in &**fields { - visitor.visit_expr(&visitor.thir()[field.expr]); - } - if let Some(base) = base { - visitor.visit_expr(&visitor.thir()[base.base]); - } - } - PlaceTypeAscription { source, user_ty: _ } - | ValueTypeAscription { source, user_ty: _ } => { - visitor.visit_expr(&visitor.thir()[source]) - } - Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} - Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), - StaticRef { literal, def_id: _ } => visitor.visit_const(literal), - InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { - for op in &**operands { - use InlineAsmOperand::*; - match op { - In { expr, reg: _ } - | Out { expr: Some(expr), reg: _, late: _ } - | InOut { expr, reg: _, late: _ } - | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), - SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - visitor.visit_expr(&visitor.thir()[*in_expr]); - if let Some(out_expr) = out_expr { - visitor.visit_expr(&visitor.thir()[*out_expr]); - } - } - Out { expr: None, reg: _, late: _ } - | Const { value: _, span: _ } - | SymStatic { def_id: _ } => {} - } - } - } - ThreadLocalRef(_) => {} - LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { - for &out_expr in &**outputs { - visitor.visit_expr(&visitor.thir()[out_expr]); - } - for &in_expr in &**inputs { - visitor.visit_expr(&visitor.thir()[in_expr]); - } - } - Yield { value } => visitor.visit_expr(&visitor.thir()[value]), - } - } - - pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { - match &stmt.kind { - StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), - StmtKind::Let { - initializer, - remainder_scope: _, - init_scope: _, - ref pattern, - lint_level: _, - } => { - if let Some(init) = initializer { - visitor.visit_expr(&visitor.thir()[*init]); - } - visitor.visit_pat(pattern); - } - } - } - - pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { - for &stmt in &*block.stmts { - visitor.visit_stmt(&visitor.thir()[stmt]); - } - if let Some(expr) = block.expr { - visitor.visit_expr(&visitor.thir()[expr]); - } - } - - pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { - match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), - Some(Guard::IfLet(ref pat, expr)) => { - visitor.visit_pat(pat); - visitor.visit_expr(&visitor.thir()[expr]); - } - None => {} - } - visitor.visit_pat(&arm.pattern); - visitor.visit_expr(&visitor.thir()[arm.body]); - } - - pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { - use PatKind::*; - match pat.kind.as_ref() { - AscribeUserType { subpattern, ascription: _ } - | Deref { subpattern } - | Binding { - subpattern: Some(subpattern), - mutability: _, - mode: _, - var: _, - ty: _, - is_primary: _, - name: _, - } => visitor.visit_pat(&subpattern), - Binding { .. } | Wild => {} - Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } - | Leaf { subpatterns } => { - for subpattern in subpatterns { - visitor.visit_pat(&subpattern.pattern); - } - } - Constant { value } => visitor.visit_const(value), - Range(range) => { - visitor.visit_const(range.lo); - visitor.visit_const(range.hi); - } - Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { - for subpattern in prefix { - visitor.visit_pat(&subpattern); - } - if let Some(pat) = slice { - visitor.visit_pat(pat); - } - for subpattern in suffix { - visitor.visit_pat(&subpattern); - } - } - Or { pats } => { - for pat in pats { - visitor.visit_pat(&pat); - } - } - }; - } -} diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs similarity index 100% rename from compiler/rustc_middle/src/mir/abstract_const.rs rename to compiler/rustc_middle/src/thir/abstract_const.rs diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs new file mode 100644 index 0000000000000..21826ac89d3a9 --- /dev/null +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -0,0 +1,238 @@ +use super::*; +pub trait Visitor<'a, 'tcx: 'a>: Sized { + fn thir(&self) -> &'a Thir<'tcx>; + + fn visit_expr(&mut self, expr: &Expr<'tcx>) { + walk_expr(self, expr); + } + + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { + walk_stmt(self, stmt); + } + + fn visit_block(&mut self, block: &Block) { + walk_block(self, block); + } + + fn visit_arm(&mut self, arm: &Arm<'tcx>) { + walk_arm(self, arm); + } + + fn visit_pat(&mut self, pat: &Pat<'tcx>) { + walk_pat(self, pat); + } + + fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} +} + +pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { + use ExprKind::*; + match expr.kind { + Scope { value, region_scope: _, lint_level: _ } => { + visitor.visit_expr(&visitor.thir()[value]) + } + Box { value } => visitor.visit_expr(&visitor.thir()[value]), + If { cond, then, else_opt, if_then_scope: _ } => { + visitor.visit_expr(&visitor.thir()[cond]); + visitor.visit_expr(&visitor.thir()[then]); + if let Some(else_expr) = else_opt { + visitor.visit_expr(&visitor.thir()[else_expr]); + } + } + Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { + visitor.visit_expr(&visitor.thir()[fun]); + for &arg in &**args { + visitor.visit_expr(&visitor.thir()[arg]); + } + } + Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), + Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Cast { source } => visitor.visit_expr(&visitor.thir()[source]), + Use { source } => visitor.visit_expr(&visitor.thir()[source]), + NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), + Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + Let { expr, .. } => { + visitor.visit_expr(&visitor.thir()[expr]); + } + Loop { body } => visitor.visit_expr(&visitor.thir()[body]), + Match { scrutinee, ref arms } => { + visitor.visit_expr(&visitor.thir()[scrutinee]); + for &arm in &**arms { + visitor.visit_arm(&visitor.thir()[arm]); + } + } + Block { ref body } => visitor.visit_block(body), + Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), + Index { lhs, index } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[index]); + } + VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} + Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), + AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Break { value, label: _ } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + Continue { label: _ } => {} + Return { value } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + ConstBlock { value } => visitor.visit_const(value), + Repeat { value, count } => { + visitor.visit_expr(&visitor.thir()[value]); + visitor.visit_const(count); + } + Array { ref fields } | Tuple { ref fields } => { + for &field in &**fields { + visitor.visit_expr(&visitor.thir()[field]); + } + } + Adt(box crate::thir::Adt { + ref fields, + ref base, + adt_def: _, + variant_index: _, + substs: _, + user_ty: _, + }) => { + for field in &**fields { + visitor.visit_expr(&visitor.thir()[field.expr]); + } + if let Some(base) = base { + visitor.visit_expr(&visitor.thir()[base.base]); + } + } + PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { + visitor.visit_expr(&visitor.thir()[source]) + } + Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} + Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), + StaticRef { literal, def_id: _ } => visitor.visit_const(literal), + InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + for op in &**operands { + use InlineAsmOperand::*; + match op { + In { expr, reg: _ } + | Out { expr: Some(expr), reg: _, late: _ } + | InOut { expr, reg: _, late: _ } + | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), + SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + visitor.visit_expr(&visitor.thir()[*in_expr]); + if let Some(out_expr) = out_expr { + visitor.visit_expr(&visitor.thir()[*out_expr]); + } + } + Out { expr: None, reg: _, late: _ } + | Const { value: _, span: _ } + | SymStatic { def_id: _ } => {} + } + } + } + ThreadLocalRef(_) => {} + LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { + for &out_expr in &**outputs { + visitor.visit_expr(&visitor.thir()[out_expr]); + } + for &in_expr in &**inputs { + visitor.visit_expr(&visitor.thir()[in_expr]); + } + } + Yield { value } => visitor.visit_expr(&visitor.thir()[value]), + } +} + +pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { + match &stmt.kind { + StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), + StmtKind::Let { + initializer, + remainder_scope: _, + init_scope: _, + ref pattern, + lint_level: _, + } => { + if let Some(init) = initializer { + visitor.visit_expr(&visitor.thir()[*init]); + } + visitor.visit_pat(pattern); + } + } +} + +pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { + for &stmt in &*block.stmts { + visitor.visit_stmt(&visitor.thir()[stmt]); + } + if let Some(expr) = block.expr { + visitor.visit_expr(&visitor.thir()[expr]); + } +} + +pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { + match arm.guard { + Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), + Some(Guard::IfLet(ref pat, expr)) => { + visitor.visit_pat(pat); + visitor.visit_expr(&visitor.thir()[expr]); + } + None => {} + } + visitor.visit_pat(&arm.pattern); + visitor.visit_expr(&visitor.thir()[arm.body]); +} + +pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { + use PatKind::*; + match pat.kind.as_ref() { + AscribeUserType { subpattern, ascription: _ } + | Deref { subpattern } + | Binding { + subpattern: Some(subpattern), + mutability: _, + mode: _, + var: _, + ty: _, + is_primary: _, + name: _, + } => visitor.visit_pat(&subpattern), + Binding { .. } | Wild => {} + Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => { + for subpattern in subpatterns { + visitor.visit_pat(&subpattern.pattern); + } + } + Constant { value } => visitor.visit_const(value), + Range(range) => { + visitor.visit_const(range.lo); + visitor.visit_const(range.hi); + } + Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { + for subpattern in prefix { + visitor.visit_pat(&subpattern); + } + if let Some(pat) = slice { + visitor.visit_pat(pat); + } + for subpattern in suffix { + visitor.visit_pat(&subpattern); + } + } + Or { pats } => { + for pat in pats { + visitor.visit_pat(&pat); + } + } + }; +} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 74edb17fe32f1..e21a2d1034cdd 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -9,7 +9,7 @@ pub mod specialization_graph; mod structural_impls; use crate::infer::canonical::Canonical; -use crate::mir::abstract_const::NotConstEvaluatable; +use crate::thir::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtKind, Ty, TyCtxt}; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 4edb6a327b035..8b70692960df9 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -12,6 +12,7 @@ use crate::mir::{ self, interpret::{AllocId, Allocation}, }; +use crate::thir; use crate::ty::subst::SubstsRef; use crate::ty::{self, List, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; @@ -362,7 +363,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) @@ -372,7 +373,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e931c686dde59..0ee740a646359 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -48,11 +48,11 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ match def { ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)); - tcx.ensure().mir_abstract_const_of_const_arg((did, const_param_did)); + tcx.ensure().thir_abstract_const_of_const_arg((did, const_param_did)); } ty::WithOptConstParam { did, const_param_did: None } => { tcx.ensure().thir_check_unsafety(did); - tcx.ensure().mir_abstract_const(did); + tcx.ensure().thir_abstract_const(did); } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 22abce65a4b7d..20232e635a2b8 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -307,7 +307,6 @@ fn mir_promoted( // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. let _ = tcx.mir_const_qualif_opt_const_arg(def); - let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global()); let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 910249ecc479e..4dcb98ae7e960 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -19,8 +19,8 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; -use rustc_middle::mir::abstract_const::Node as ACNode; use rustc_middle::span_bug; +use rustc_middle::thir::abstract_const::Node as ACNode; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 5c2803c67e73f..2903e220b3b07 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -9,6 +9,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret}; +use rustc_middle::thir; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; @@ -906,7 +907,7 @@ impl<'a, 'tcx> Decodable> } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { RefDecodable::decode(d) } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4251dc5e93904..8c2a3d4abf41b 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -6,7 +6,7 @@ //! this is not as easy. //! //! In this case we try to build an abstract representation of this constant using -//! `mir_abstract_const` which can then be checked for structural equality with other +//! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; @@ -14,9 +14,9 @@ use rustc_hir::def::DefKind; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir; -use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir; +use rustc_middle::thir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -197,7 +197,7 @@ impl<'tcx> AbstractConst<'tcx> { tcx: TyCtxt<'tcx>, uv: ty::Unevaluated<'tcx, ()>, ) -> Result>, ErrorReported> { - let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?; + let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; debug!("AbstractConst::new({:?}) = {:?}", uv, inner); Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) })) } @@ -421,10 +421,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. -pub(super) fn mir_abstract_const<'tcx>( +pub(super) fn thir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, -) -> Result]>, ErrorReported> { +) -> Result]>, ErrorReported> { if tcx.features().generic_const_exprs { match tcx.def_kind(def.did) { // FIXME(generic_const_exprs): We currently only do this for anonymous constants, @@ -435,7 +435,7 @@ pub(super) fn mir_abstract_const<'tcx>( DefKind::AnonConst => (), _ => return Ok(None), } - + let body = tcx.thir_body(def); if body.0.borrow().exprs.is_empty() { // type error in constant, there is no thir 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 9ce6c58a0f1df..4d3a8324d7987 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -19,7 +19,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{ diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 18abcc72bcee8..b376f42929249 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -5,8 +5,8 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 44c675243838a..ef208c44471cb 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -827,16 +827,16 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, - mir_abstract_const: |tcx, def_id| { + thir_abstract_const: |tcx, def_id| { let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.mir_abstract_const_of_const_arg(def) + tcx.thir_abstract_const_of_const_arg(def) } else { - const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) } }, - mir_abstract_const_of_const_arg: |tcx, (did, param_did)| { - const_evaluatable::mir_abstract_const( + thir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + const_evaluatable::thir_abstract_const( tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }, ) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 63bd10994b1ac..e001bb7445e8c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -836,7 +836,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // // This shouldn't really matter though as we can't really use any // constants which are not considered const evaluatable. - use rustc_middle::mir::abstract_const::Node; + use rustc_middle::thir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 22013fb79cf79..01a38ffa7d0b2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -34,8 +34,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; From 79be0802557089b408776ba161d95f8f4b5d0683 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 03:02:12 +0100 Subject: [PATCH 16/32] remove comment --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8c2a3d4abf41b..1aaed7cade281 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Repeat { .. } | ExprKind::Array { .. } | ExprKind::Block { .. } - | ExprKind::NeverToAny { .. } // I dont think we can get this without adt construction + | ExprKind::NeverToAny { .. } | ExprKind::Tuple { .. } | ExprKind::Index { .. } | ExprKind::Field { .. } From 955e2b2da0ca29042206a56060baa820a2d961e7 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 12:05:11 +0100 Subject: [PATCH 17/32] nits --- compiler/rustc_middle/src/mir/query.rs | 13 ------- .../rustc_middle/src/thir/abstract_const.rs | 23 +++++++++-- compiler/rustc_middle/src/thir/visit.rs | 6 ++- .../src/traits/const_evaluatable.rs | 39 +++++++++---------- 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a1c6a8bf99e79..567f65e83d98c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,7 +1,6 @@ //! Values computed by queries that use MIR. use crate::mir::{Body, Promoted}; -use crate::thir::abstract_const; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; @@ -432,16 +431,4 @@ impl<'tcx> TyCtxt<'tcx> { self.mir_for_ctfe(def.did) } } - - #[inline] - pub fn thir_abstract_const_opt_const_arg( - self, - def: ty::WithOptConstParam, - ) -> Result]>, ErrorReported> { - if let Some((did, param_did)) = def.as_const_arg() { - self.thir_abstract_const_of_const_arg((did, param_did)) - } else { - self.thir_abstract_const(def.did) - } - } } diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs index 27849e4bdb0bf..00f1390eb4d4e 100644 --- a/compiler/rustc_middle/src/thir/abstract_const.rs +++ b/compiler/rustc_middle/src/thir/abstract_const.rs @@ -1,6 +1,7 @@ //! A subset of a mir body used for const evaluatability checking. use crate::mir; -use crate::ty::{self, Ty}; +use crate::ty::{self, Ty, TyCtxt}; +use rustc_errors::ErrorReported; rustc_index::newtype_index! { /// An index into an `AbstractConst`. @@ -22,13 +23,13 @@ pub enum Node<'tcx> { #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum NotConstEvaluatable { - Error(rustc_errors::ErrorReported), + Error(ErrorReported), MentionsInfer, MentionsParam, } -impl From for NotConstEvaluatable { - fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable { +impl From for NotConstEvaluatable { + fn from(e: ErrorReported) -> NotConstEvaluatable { NotConstEvaluatable::Error(e) } } @@ -36,3 +37,17 @@ impl From for NotConstEvaluatable { TrivialTypeFoldableAndLiftImpls! { NotConstEvaluatable, } + +impl<'tcx> TyCtxt<'tcx> { + #[inline] + pub fn thir_abstract_const_opt_const_arg( + self, + def: ty::WithOptConstParam, + ) -> Result]>, ErrorReported> { + if let Some((did, param_did)) = def.as_const_arg() { + self.thir_abstract_const_of_const_arg((did, param_did)) + } else { + self.thir_abstract_const(def.did) + } + } +} diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 21826ac89d3a9..7fc15e02fcd30 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -1,4 +1,8 @@ -use super::*; +use super::{ + Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, +}; +use rustc_middle::ty::Const; + pub trait Visitor<'a, 'tcx: 'a>: Sized { fn thir(&self) -> &'a Thir<'tcx>; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1aaed7cade281..1845b9d1314b1 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,7 +8,6 @@ //! In this case we try to build an abstract representation of this constant using //! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; use rustc_index::vec::IndexVec; @@ -227,8 +226,7 @@ impl<'tcx> AbstractConst<'tcx> { struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, body_id: thir::ExprId, - /// `Lrc` is used to avoid borrowck difficulties in `recurse_build` - body: Lrc<&'a thir::Thir<'tcx>>, + body: &'a thir::Thir<'tcx>, /// The current WIP node tree. nodes: IndexVec>, } @@ -253,8 +251,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), ) -> Result>, ErrorReported> { - let builder = - AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() }; + let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() }; struct IsThirPolymorphic<'a, 'tcx> { is_poly: bool, @@ -328,7 +325,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn recurse_build(&mut self, node: thir::ExprId) -> Result { use thir::ExprKind; - let node = &self.body.clone().exprs[node]; + let node = &self.body.exprs[node]; debug!("recurse_build: node={:?}", node); Ok(match &node.kind { // I dont know if handling of these 3 is correct @@ -338,10 +335,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // subtle: associated consts are literals this arm handles // `::ASSOC` as well as `12` - &ExprKind::Literal { literal, .. } - | &ExprKind::StaticRef { literal, .. } => self.nodes.push(Node::Leaf(literal)), + &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), - // FIXME(generic_const_exprs) handle `from_hir_call` field + // FIXME(generic_const_exprs): Handle `from_hir_call` field ExprKind::Call { fun, args, .. } => { let fun = self.recurse_build(*fun)?; @@ -361,7 +357,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(arg)?; self.nodes.push(Node::UnaryOp(op, arg)) }, - // this is necessary so that the following compiles: + // This is necessary so that the following compiles: // // ``` // fn foo(a: [(); N + 1]) { @@ -369,16 +365,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // } // ``` ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, - // ExprKind::Use happens when a `hir::ExprKind::Cast` is a + // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. - // this is important so that `N as usize as usize` doesnt unify with `N as usize` + // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) &ExprKind::Use { source} | &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(arg, node.ty)) }, - // FIXME(generic_const_exprs) we want to support these + // FIXME(generic_const_exprs): We may want to support these. ExprKind::AddressOf { .. } | ExprKind::Borrow { .. } | ExprKind::Deref { .. } @@ -390,21 +386,24 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Index { .. } | ExprKind::Field { .. } | ExprKind::ConstBlock { .. } - | ExprKind::Adt(_) => return self.error( + | ExprKind::Adt(_) => self.error( Some(node.span), "unsupported operation in generic constant, this may be supported in the future", - ).map(|never| never), + )?, ExprKind::Match { .. } - | ExprKind::VarRef { .. } // - | ExprKind::UpvarRef { .. } // we dont permit let stmts so... + // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen + | ExprKind::VarRef { .. } + | ExprKind::UpvarRef { .. } | ExprKind::Closure { .. } | ExprKind::Let { .. } // let expressions imply control flow | ExprKind::Loop { .. } | ExprKind::Assign { .. } + | ExprKind::StaticRef { .. } | ExprKind::LogicalOp { .. } - | ExprKind::Unary { .. } // - | ExprKind::Binary { .. } // we handle valid unary/binary ops above + // we handle valid unary/binary ops above + | ExprKind::Unary { .. } + | ExprKind::Binary { .. } | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::If { .. } @@ -415,7 +414,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Box { .. } // allocations not allowed in constants | ExprKind::AssignOp { .. } | ExprKind::InlineAsm { .. } - | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never), + | ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?, }) } } From 8c7954dc425e8c6ee4aaaf14be5015ad8982d540 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 13:24:04 +0100 Subject: [PATCH 18/32] add a `CastKind` to `Node::Cast` --- .../rustc_middle/src/thir/abstract_const.rs | 10 +++++++++- compiler/rustc_privacy/src/lib.rs | 2 +- .../src/traits/const_evaluatable.rs | 17 ++++++++++------- .../src/traits/object_safety.rs | 2 +- .../abstract-consts-as-cast-5.rs | 11 +++++++++++ .../abstract-consts-as-cast-5.stderr | 10 ++++++++++ 6 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs index 00f1390eb4d4e..f80beadd6e551 100644 --- a/compiler/rustc_middle/src/thir/abstract_const.rs +++ b/compiler/rustc_middle/src/thir/abstract_const.rs @@ -11,6 +11,14 @@ rustc_index::newtype_index! { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum CastKind { + /// thir::ExprKind::As + As, + /// thir::ExprKind::Use + Use, +} + /// A node of an `AbstractConst`. #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum Node<'tcx> { @@ -18,7 +26,7 @@ pub enum Node<'tcx> { Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), - Cast(NodeId, Ty<'tcx>), + Cast(CastKind, NodeId, Ty<'tcx>), } #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4dcb98ae7e960..391e43054239d 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -158,7 +158,7 @@ where let leaf = leaf.subst(tcx, ct.substs); self.visit_const(leaf) } - ACNode::Cast(_, ty) => self.visit_ty(ty), + ACNode::Cast(_, _, ty) => self.visit_ty(ty), ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { ControlFlow::CONTINUE } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1845b9d1314b1..26c71a0f53921 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir; -use rustc_middle::thir::abstract_const::{Node, NodeId, NotConstEvaluatable}; +use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -91,7 +91,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Cast(_, ty) => { + Node::Cast(_, _, ty) => { let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; @@ -368,10 +368,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) - &ExprKind::Use { source} - | &ExprKind::Cast { source } => { + &ExprKind::Use { source } => { let arg = self.recurse_build(source)?; - self.nodes.push(Node::Cast(arg, node.ty)) + self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty)) + }, + &ExprKind::Cast { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty)) }, // FIXME(generic_const_exprs): We may want to support these. @@ -494,7 +497,7 @@ where recurse(tcx, ct.subtree(func), f)?; args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } - Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f), + Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), } } @@ -577,7 +580,7 @@ pub(super) fn try_unify<'tcx>( && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } - (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty)) if (a_ty == b_ty) => { + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) if (a_ty == b_ty) && (a_kind == b_kind) => { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } // use this over `_ => false` to make adding variants to `Node` less error prone diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index e001bb7445e8c..70cdbe4d5c7cb 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -843,7 +843,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } - Node::Cast(_, ty) => self.visit_ty(ty), + Node::Cast(_, _, ty) => self.visit_ty(ty), Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { ControlFlow::CONTINUE } diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs new file mode 100644 index 0000000000000..b3cde61f5e7f2 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs @@ -0,0 +1,11 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +fn foo(a: [(); N as usize]) { + bar::<{ N as usize as usize }>(); + //~^ error: unconstrained generic constant +} + +fn bar() {} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr new file mode 100644 index 0000000000000..d48b639dbdee3 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/abstract-consts-as-cast-5.rs:5:11 + | +LL | bar::<{ N as usize as usize }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N as usize as usize }]:` + +error: aborting due to previous error + From 3212734bd744719dc197a19902d083c591670ab1 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 13:36:50 +0100 Subject: [PATCH 19/32] resolve `from_hir_call` FIXME --- .../src/traits/const_evaluatable.rs | 1 - .../abstract-consts-as-cast-5.rs | 2 +- .../unify-op-with-fn-call.rs | 23 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 26c71a0f53921..702b5a508b744 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -337,7 +337,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), - // FIXME(generic_const_exprs): Handle `from_hir_call` field ExprKind::Call { fun, args, .. } => { let fun = self.recurse_build(*fun)?; diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs index b3cde61f5e7f2..916d60c0e0def 100644 --- a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs @@ -8,4 +8,4 @@ fn foo(a: [(); N as usize]) { fn bar() {} -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs new file mode 100644 index 0000000000000..abbeb2c928ed4 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -0,0 +1,23 @@ +#![feature(generic_const_exprs, adt_const_params, const_trait_impl)] +#![allow(incomplete_features)] + +#[derive(PartialEq, Eq)] +struct Foo(u8); + +impl const std::ops::Add for Foo { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + self + } +} + +struct Evaluatable; + +fn foo(a: Evaluatable<{ N + N }>) { + bar::<{ std::ops::Add::add(N, N) }>(); +} + +fn bar() {} + +fn main() {} From cd2915eddb446df2d89922d3b68080d091dc247e Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 13:49:31 +0100 Subject: [PATCH 20/32] fmt --- .../rustc_trait_selection/src/traits/const_evaluatable.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 702b5a508b744..4f178f777afb2 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -579,7 +579,9 @@ pub(super) fn try_unify<'tcx>( && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } - (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) if (a_ty == b_ty) && (a_kind == b_kind) => { + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) + if (a_ty == b_ty) && (a_kind == b_kind) => + { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } // use this over `_ => false` to make adding variants to `Node` less error prone From fd9bb30ab8fc65da735272f9cfd55d1368da9069 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 14:27:07 +0100 Subject: [PATCH 21/32] CI please --- .../const-generics/generic_const_exprs/unify-op-with-fn-call.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs index abbeb2c928ed4..bb054bec6b6c2 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -1,3 +1,4 @@ +// check-pass #![feature(generic_const_exprs, adt_const_params, const_trait_impl)] #![allow(incomplete_features)] From 8295e4a6cfb12ce74c480172c2854f76d1428b8b Mon Sep 17 00:00:00 2001 From: Ellen Date: Thu, 9 Sep 2021 15:43:59 +0100 Subject: [PATCH 22/32] add test for builtin types N + N unifying with fn call --- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- .../src/traits/const_evaluatable.rs | 13 ++++++++++--- .../generic_const_exprs/unify-op-with-fn-call.rs | 13 ++++++++++++- .../unify-op-with-fn-call.stderr | 10 ++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 60d7f0f85bb57..97c0bca5d911c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1305,7 +1305,7 @@ impl EncodeContext<'a, 'tcx> { if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); - // FIXME this feels wrong to have in `encode_mir` + // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir` let abstract_const = self.tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4f178f777afb2..24fa5007f1ecd 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -267,10 +267,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); - if self.is_poly { - return; + if self.is_poly == false { + visit::walk_expr(self, expr) + } + } + + fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { + self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx); + if self.is_poly == false { + visit::walk_pat(self, pat); } - visit::walk_expr(self, expr); } fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { @@ -280,6 +286,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; visit::walk_expr(&mut is_poly_vis, &body[body_id]); + debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); if is_poly_vis.is_poly == false { return Ok(None); } diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs index bb054bec6b6c2..c0404d35b0887 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -1,7 +1,7 @@ -// check-pass #![feature(generic_const_exprs, adt_const_params, const_trait_impl)] #![allow(incomplete_features)] +// test `N + N` unifies with explicit function calls for non-builtin-types #[derive(PartialEq, Eq)] struct Foo(u8); @@ -21,4 +21,15 @@ fn foo(a: Evaluatable<{ N + N }>) { fn bar() {} +// test that `N + N` unifies with explicit function calls for builin-types +struct Evaluatable2; + +fn foo2(a: Evaluatable2<{ N + N }>) { + bar2::<{ std::ops::Add::add(N, N) }>(); + //~^ error: unconstrained generic constant + // FIXME(generic_const_exprs) make this not an error +} + +fn bar2() {} + fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr new file mode 100644 index 0000000000000..d18c7916f5f6f --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/unify-op-with-fn-call.rs:28:12 + | +LL | bar2::<{ std::ops::Add::add(N, N) }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { std::ops::Add::add(N, N) }]:` + +error: aborting due to previous error + From 44e6f2e90fa050c490c2d79a3c65866cb5be3b34 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 21 Aug 2021 20:58:23 -0700 Subject: [PATCH 23/32] Remove unnecessary `Cache.*_did` fields They can be obtained by accessing the `TyCtxt` where they are needed. --- src/librustdoc/clean/utils.rs | 4 --- src/librustdoc/formats/cache.rs | 3 --- src/librustdoc/html/render/mod.rs | 41 ++++++++++++++----------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index de2cd60d2edcd..873ecd759ebbd 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -29,10 +29,6 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { let krate = cx.tcx.hir().krate(); let module = crate::visit_ast::RustdocVisitor::new(cx).visit(krate); - cx.cache.deref_trait_did = cx.tcx.lang_items().deref_trait(); - cx.cache.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); - cx.cache.owned_box_did = cx.tcx.lang_items().owned_box(); - let mut externs = Vec::new(); for &cnum in cx.tcx.crates(()).iter() { externs.push(ExternalCrate { crate_num: cnum }); diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 1830909d94460..a88f82dadda12 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -98,9 +98,6 @@ crate struct Cache { stripped_mod: bool, crate search_index: Vec, - crate deref_trait_did: Option, - crate deref_mut_trait_did: Option, - crate owned_box_did: Option, // In rare case where a structure is defined in one module but implemented // in another, if the implementing module is parsed before defining module, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 172fe5d164b7a..f8f71c6f3daf3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1069,13 +1069,13 @@ fn render_assoc_items( return; } if !traits.is_empty() { - let deref_impl = traits - .iter() - .find(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did); + let deref_impl = traits.iter().find(|t| { + t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait() + }); if let Some(impl_) = deref_impl { - let has_deref_mut = traits - .iter() - .any(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_mut_trait_did); + let has_deref_mut = traits.iter().any(|t| { + t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_mut_trait() + }); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); } let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = @@ -1165,7 +1165,7 @@ fn render_deref_methods( } } -fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool { +fn should_render_item(item: &clean::Item, deref_mut_: bool, cx: &Context<'_>) -> bool { let self_type_opt = match *item.kind { clean::MethodItem(ref method, _) => method.decl.self_type(), clean::TyMethodItem(ref method) => method.decl.self_type(), @@ -1179,7 +1179,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bo (mutability == Mutability::Mut, false, false) } SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => { - (false, Some(did) == cache.owned_box_did, false) + (false, Some(did) == cx.tcx().lang_items().owned_box(), false) } SelfTy::SelfValue => (false, false, true), _ => (false, false, false), @@ -1302,7 +1302,7 @@ fn render_impl( && match render_mode { RenderMode::Normal => true, RenderMode::ForDeref { mut_: deref_mut_ } => { - should_render_item(&item, deref_mut_, cx.cache()) + should_render_item(&item, deref_mut_, cx) } }; @@ -1800,13 +1800,13 @@ fn get_methods( for_deref: bool, used_links: &mut FxHashSet, deref_mut: bool, - cache: &Cache, + cx: &Context<'_>, ) -> Vec { i.items .iter() .filter_map(|item| match item.name { Some(ref name) if !name.is_empty() && item.is_method() => { - if !for_deref || should_render_item(item, deref_mut, cache) { + if !for_deref || should_render_item(item, deref_mut, cx) { Some(format!( "{}", get_next_url(used_links, format!("method.{}", name)), @@ -1868,7 +1868,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { let mut ret = v .iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false, cache)) + .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false, cx)) .collect::>(); if !ret.is_empty() { // We want links' order to be reproducible so we don't use unstable sort. @@ -1886,11 +1886,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { } if v.iter().any(|i| i.inner_impl().trait_.is_some()) { - if let Some(impl_) = v - .iter() - .filter(|i| i.inner_impl().trait_.is_some()) - .find(|i| i.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did) - { + if let Some(impl_) = v.iter().filter(|i| i.inner_impl().trait_.is_some()).find(|i| { + i.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait() + }) { sidebar_deref_methods(cx, out, impl_, v); } @@ -1988,10 +1986,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V } } } - let deref_mut = v - .iter() - .filter(|i| i.inner_impl().trait_.is_some()) - .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did); + let deref_mut = v.iter().filter(|i| i.inner_impl().trait_.is_some()).any(|i| { + i.inner_impl().trait_.def_id_full(c) == cx.tcx().lang_items().deref_mut_trait() + }); let inner_impl = target .def_id_full(c) .or_else(|| { @@ -2004,7 +2001,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V let mut ret = impls .iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c)) + .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx)) .collect::>(); if !ret.is_empty() { write!( From 294510e1bb7e03bd462f6a6db2fab5f56fae1c8c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 5 Sep 2021 23:37:15 +0300 Subject: [PATCH 24/32] rustc: Remove local variable IDs from `Export`s Local variables can never be exported. --- compiler/rustc_data_structures/src/lib.rs | 1 + .../src/stable_hasher.rs | 6 +++ compiler/rustc_hir/src/def.rs | 5 +++ compiler/rustc_metadata/src/rmeta/decoder.rs | 5 +-- .../src/rmeta/decoder/cstore_impl.rs | 40 ++++++++----------- compiler/rustc_metadata/src/rmeta/encoder.rs | 9 +---- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/hir/exports.rs | 13 ++---- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 4 +- compiler/rustc_resolve/src/imports.rs | 5 +-- compiler/rustc_resolve/src/lib.rs | 3 +- compiler/rustc_serialize/src/serialize.rs | 12 ++++++ .../rustc_typeck/src/check/method/suggest.rs | 2 +- src/librustdoc/clean/inline.rs | 11 +++-- src/librustdoc/clean/types.rs | 9 +++-- src/librustdoc/visit_lib.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 4 +- 19 files changed, 71 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index d128a688e751f..dd6a17b92aef3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -21,6 +21,7 @@ #![feature(iter_map_while)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] +#![feature(never_type)] #![feature(type_alias_impl_trait)] #![feature(new_uninit)] #![feature(nll)] diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 18b352cf3b0b9..354f9dd93cc4d 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -209,6 +209,12 @@ impl_stable_hash_via_hash!(i128); impl_stable_hash_via_hash!(char); impl_stable_hash_via_hash!(()); +impl HashStable for ! { + fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) { + unreachable!() + } +} + impl HashStable for ::std::num::NonZeroU32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { self.get().hash_stable(ctx, hasher) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 853415c4173b5..cb668eb35e093 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -598,6 +598,11 @@ impl Res { } } + #[track_caller] + pub fn expect_non_local(self) -> Res { + self.map_id(|_| panic!("unexpected `Res::Local`")) + } + pub fn macro_kind(self) -> Option { match self { Res::Def(DefKind::Macro(kind), _) => Some(kind), diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index dd44e0cb1fa90..0c284269c2fe3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1019,10 +1019,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over each child of the given item. - fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) - where - F: FnMut(Export), - { + fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) { if let Some(data) = &self.root.proc_macro_data { /* If we are loading as a proc macro, we want to return the view of this crate * as a proc macro crate. diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 41839c58021ab..80341b16e1412 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -5,7 +5,6 @@ use crate::rmeta::encoder; use rustc_ast as ast; use rustc_data_structures::stable_map::FxHashMap; -use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; @@ -326,28 +325,27 @@ pub fn provide(providers: &mut Providers) { // (restrict scope of mutable-borrow of `visible_parent_map`) { let visible_parent_map = &mut visible_parent_map; - let mut add_child = - |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { - if child.vis != ty::Visibility::Public { - return; - } + let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { + if child.vis != ty::Visibility::Public { + return; + } - if let Some(child) = child.res.opt_def_id() { - match visible_parent_map.entry(child) { - Entry::Occupied(mut entry) => { - // If `child` is defined in crate `cnum`, ensure - // that it is mapped to a parent in `cnum`. - if child.is_local() && entry.get().is_local() { - entry.insert(parent); - } - } - Entry::Vacant(entry) => { + if let Some(child) = child.res.opt_def_id() { + match visible_parent_map.entry(child) { + Entry::Occupied(mut entry) => { + // If `child` is defined in crate `cnum`, ensure + // that it is mapped to a parent in `cnum`. + if child.is_local() && entry.get().is_local() { entry.insert(parent); - bfs_queue.push_back(child); } } + Entry::Vacant(entry) => { + entry.insert(parent); + bfs_queue.push_back(child); + } } - }; + } + }; while let Some(def) = bfs_queue.pop_front() { for child in tcx.item_children(def).iter() { @@ -393,11 +391,7 @@ impl CStore { self.get_crate_data(def.krate).get_visibility(def.index) } - pub fn item_children_untracked( - &self, - def_id: DefId, - sess: &Session, - ) -> Vec> { + pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec { let mut result = vec![]; self.get_crate_data(def_id.krate).each_child_of_item( def_id.index, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d8b9a4799760e..52c6193940dbc 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1065,14 +1065,7 @@ impl EncodeContext<'a, 'tcx> { // items - we encode information about proc-macros later on. let reexports = if !self.is_proc_macro { match tcx.module_exports(local_def_id) { - Some(exports) => { - let hir = self.tcx.hir(); - self.lazy( - exports - .iter() - .map(|export| export.map_id(|id| hir.local_def_id_to_hir_id(id))), - ) - } + Some(exports) => self.lazy(exports), _ => Lazy::empty(), } } else { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a487753f4628a..fe0bf5b64ba09 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -359,7 +359,7 @@ struct RenderedConst(String); #[derive(MetadataEncodable, MetadataDecodable)] struct ModData { - reexports: Lazy<[Export]>, + reexports: Lazy<[Export]>, expansion: ExpnId, } diff --git a/compiler/rustc_middle/src/hir/exports.rs b/compiler/rustc_middle/src/hir/exports.rs index be9e38aca65d1..f37b976fba68d 100644 --- a/compiler/rustc_middle/src/hir/exports.rs +++ b/compiler/rustc_middle/src/hir/exports.rs @@ -11,23 +11,18 @@ use std::fmt::Debug; /// This is the replacement export map. It maps a module to all of the exports /// within. -pub type ExportMap = FxHashMap>>; +pub type ExportMap = FxHashMap>; #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct Export { +pub struct Export { /// The name of the target. pub ident: Ident, /// The resolution of the target. - pub res: Res, + /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter. + pub res: Res, /// The span of the target. pub span: Span, /// The visibility of the export. /// We include non-`pub` exports for hygienic macros that get used from extern crates. pub vis: ty::Visibility, } - -impl Export { - pub fn map_id(self, map: impl FnMut(Id) -> R) -> Export { - Export { ident: self.ident, res: self.res.map_id(map), span: self.span, vis: self.vis } - } -} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c93996162e3e3..3b07be460db9b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1181,7 +1181,7 @@ rustc_queries! { desc { "traits in scope at a block" } } - query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> { + query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> { desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) } } @@ -1393,7 +1393,7 @@ rustc_queries! { eval_always desc { "fetching what a crate is named" } } - query item_children(def_id: DefId) -> &'tcx [Export] { + query item_children(def_id: DefId) -> &'tcx [Export] { desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) } } query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fddfd6e435c05..cd1e38445ae8c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -127,7 +127,7 @@ pub struct ResolverOutputs { pub extern_crate_map: FxHashMap, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, - pub export_map: ExportMap, + pub export_map: ExportMap, pub glob_map: FxHashMap>, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 2ee483d850e7b..55f2b04c4f1c1 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -228,7 +228,6 @@ impl<'a> Resolver<'a> { crate fn build_reduced_graph_external(&mut self, module: Module<'a>) { let def_id = module.def_id().expect("unpopulated module without a def-id"); for child in self.cstore().item_children_untracked(def_id, self.session) { - let child = child.map_id(|_| panic!("unexpected id")); let parent_scope = ParentScope::module(module, self); BuildReducedGraphVisitor { r: self, parent_scope } .build_reduced_graph_for_external_crate_res(child); @@ -946,9 +945,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) { + fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) { let parent = self.parent_scope.module; let Export { ident, res, vis, span } = child; + let res = res.expect_non_local(); let expansion = self.parent_scope.expansion; // Record primary definitions. match res { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index dfb6d89a0d126..d4782edbc1346 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -11,7 +11,6 @@ use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBindin use rustc_ast::unwrap_or; use rustc_ast::NodeId; -use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::ptr_key::PtrKey; use rustc_errors::{pluralize, struct_span_err, Applicability}; @@ -1387,13 +1386,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut reexports = Vec::new(); - module.for_each_child(self.r, |this, ident, _, binding| { + module.for_each_child(self.r, |_, ident, _, binding| { // Filter away ambiguous imports and anything that has def-site hygiene. // FIXME: Implement actual cross-crate hygiene. let is_good_import = binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion(); if is_good_import || binding.is_macro_def() { - let res = binding.res().map_id(|id| this.local_def_id(id)); + let res = binding.res().expect_non_local(); if res != def::Res::Err { reexports.push(Export { ident, res, span: binding.span, vis: binding.vis }); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6d2961db9e3da..912f0bf13fe1a 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -14,6 +14,7 @@ #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] #![feature(iter_zip)] +#![feature(never_type)] #![feature(nll)] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] @@ -911,7 +912,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, - export_map: ExportMap, + export_map: ExportMap, trait_map: Option>>, /// A map from nodes to anonymous modules. diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index ecc8dae04800a..e32e4493726db 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -366,6 +366,18 @@ direct_serialize_impls! { char emit_char read_char } +impl Encodable for ! { + fn encode(&self, _s: &mut S) -> Result<(), S::Error> { + unreachable!() + } +} + +impl Decodable for ! { + fn decode(_d: &mut D) -> Result { + unreachable!() + } +} + impl Encodable for ::std::num::NonZeroU32 { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u32(self.get()) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index a746ad7ad4bc7..9744f4f6483c7 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1655,7 +1655,7 @@ fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] { tcx: TyCtxt<'_>, traits: &mut Vec, external_mods: &mut FxHashSet, - res: Res, + res: Res, ) { match res { Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0c81a55843013..b8633f0dcfd29 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -482,12 +482,13 @@ fn build_module( // visit each node at most once. for &item in cx.tcx.item_children(did).iter() { if item.vis == ty::Visibility::Public { - if let Some(def_id) = item.res.mod_def_id() { + let res = item.res.expect_non_local(); + if let Some(def_id) = res.mod_def_id() { if did == def_id || !visited.insert(def_id) { continue; } } - if let Res::PrimTy(p) = item.res { + if let Res::PrimTy(p) = res { // Primitive types can't be inlined so generate an import instead. let prim_ty = clean::PrimitiveType::from(p); items.push(clean::Item { @@ -500,7 +501,7 @@ fn build_module( clean::ImportSource { path: clean::Path { global: false, - res: item.res, + res, segments: vec![clean::PathSegment { name: prim_ty.as_sym(), args: clean::GenericArgs::AngleBracketed { @@ -515,9 +516,7 @@ fn build_module( ))), cfg: None, }); - } else if let Some(i) = - try_inline(cx, did, None, item.res, item.ident.name, None, visited) - { + } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) { items.extend(i) } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5eff56a2200e1..8f31a42e1a2a3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -212,7 +212,7 @@ impl ExternalCrate { crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> { let root = self.def_id(); - let as_keyword = |res: Res| { + let as_keyword = |res: Res| { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = tcx.get_attrs(def_id); let mut keyword = None; @@ -243,7 +243,8 @@ impl ExternalCrate { hir::ItemKind::Use(ref path, hir::UseKind::Single) if item.vis.node.is_pub() => { - as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim)) + as_keyword(path.res.expect_non_local()) + .map(|(_, prim)| (id.def_id.to_def_id(), prim)) } _ => None, } @@ -274,7 +275,7 @@ impl ExternalCrate { // Also note that this does not attempt to deal with modules tagged // duplicately for the same primitive. This is handled later on when // rendering by delegating everything to a hash map. - let as_primitive = |res: Res| { + let as_primitive = |res: Res| { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = tcx.get_attrs(def_id); let mut prim = None; @@ -309,7 +310,7 @@ impl ExternalCrate { hir::ItemKind::Use(ref path, hir::UseKind::Single) if item.vis.node.is_pub() => { - as_primitive(path.res).map(|(_, prim)| { + as_primitive(path.res.expect_non_local()).map(|(_, prim)| { // Pretend the primitive is local. (id.def_id.to_def_id(), prim) }) diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 3e06b4173144c..3e98ba08fb9ca 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { } } - fn visit_item(&mut self, res: Res) { + fn visit_item(&mut self, res: Res) { let def_id = res.def_id(); let vis = self.tcx.visibility(def_id); let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None }; diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index da259511fe0b9..3a94f47298390 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -520,7 +520,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { } }; } - fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> { + fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> { tcx.item_children(def_id) .iter() .find(|item| item.ident.name.as_str() == name) @@ -557,7 +557,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { None } }); - try_res!(last).res + try_res!(last).res.expect_non_local() } /// Convenience function to get the `DefId` of a trait by path. From 03f9fe2f2fa2555b0598a80a3c4ad135ca2a4368 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 11 Sep 2021 20:24:46 +0200 Subject: [PATCH 25/32] explicitly link to external `ena` docs --- src/bootstrap/doc.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index c871411793073..fbc7f19cb731c 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -590,10 +590,18 @@ impl Step for Rustc { cargo.rustdocflag("-Znormalize-docs"); cargo.rustdocflag("--show-type-layout"); compile::rustc_cargo(builder, &mut cargo, target); + cargo.arg("-Zunstable-options"); cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. + // Do link to dependencies on `docs.rs` however using `rustdoc-map`. cargo.arg("--no-deps"); + cargo.arg("-Zrustdoc-map"); + + // FIXME: `-Zrustdoc-map` does not yet correctly work for transitive dependencies, + // once this is no longer an issue the special case for `ena` can be removed. + cargo.rustdocflag("--extern-html-root-url"); + cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); // Find dependencies for top level crates. let mut compiler_crates = HashSet::new(); From df281ee57b3eb04184802da552b06d1b83a04ad3 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 27 Aug 2021 16:49:14 -0700 Subject: [PATCH 26/32] Only take `tcx` when it's all that's needed --- src/librustdoc/html/render/mod.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f8f71c6f3daf3..2c32fe305edab 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -51,6 +51,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{kw, sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; @@ -1165,7 +1166,7 @@ fn render_deref_methods( } } -fn should_render_item(item: &clean::Item, deref_mut_: bool, cx: &Context<'_>) -> bool { +fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { let self_type_opt = match *item.kind { clean::MethodItem(ref method, _) => method.decl.self_type(), clean::TyMethodItem(ref method) => method.decl.self_type(), @@ -1179,7 +1180,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cx: &Context<'_>) -> (mutability == Mutability::Mut, false, false) } SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => { - (false, Some(did) == cx.tcx().lang_items().owned_box(), false) + (false, Some(did) == tcx.lang_items().owned_box(), false) } SelfTy::SelfValue => (false, false, true), _ => (false, false, false), @@ -1302,7 +1303,7 @@ fn render_impl( && match render_mode { RenderMode::Normal => true, RenderMode::ForDeref { mut_: deref_mut_ } => { - should_render_item(&item, deref_mut_, cx) + should_render_item(&item, deref_mut_, cx.tcx()) } }; @@ -1800,13 +1801,13 @@ fn get_methods( for_deref: bool, used_links: &mut FxHashSet, deref_mut: bool, - cx: &Context<'_>, + tcx: TyCtxt<'_>, ) -> Vec { i.items .iter() .filter_map(|item| match item.name { Some(ref name) if !name.is_empty() && item.is_method() => { - if !for_deref || should_render_item(item, deref_mut, cx) { + if !for_deref || should_render_item(item, deref_mut, tcx) { Some(format!( "{}", get_next_url(used_links, format!("method.{}", name)), @@ -1868,7 +1869,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { let mut ret = v .iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false, cx)) + .flat_map(move |i| { + get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx()) + }) .collect::>(); if !ret.is_empty() { // We want links' order to be reproducible so we don't use unstable sort. @@ -2001,7 +2004,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V let mut ret = impls .iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx)) + .flat_map(|i| { + get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx.tcx()) + }) .collect::>(); if !ret.is_empty() { write!( From 0bb1c285af51def917dd17ec1b1815cb34d4b208 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 22 Aug 2021 18:53:00 -0700 Subject: [PATCH 27/32] rustdoc: Get symbol for `TyParam` directly --- src/librustdoc/clean/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 873ecd759ebbd..a11b9c2af8a96 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -414,7 +414,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty return Generic(kw::SelfUpper); } Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(Symbol::intern(&path.whole_name())); + return Generic(path.segments[0].name); } Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, _ => false, From 6a84d347844afc5b228a67ac8bb147f3d0e40ddb Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 24 Aug 2021 10:33:41 -0700 Subject: [PATCH 28/32] Create a valid `Res` in `external_path()` The order of the `where` bounds on auto trait impls changed because rustdoc currently sorts auto trait `where` bounds based on the `Debug` output for the bound. Now that the bounds have an actual `Res`, they are being unintentionally sorted by their `DefId` rather than their path. So, I had to update a test for the change in ordering of the rendered bounds. --- src/librustdoc/clean/mod.rs | 19 +++++-------------- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/clean/utils.rs | 10 ++++++---- .../rustdoc/synthetic_auto/no-redundancy.rs | 2 +- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e2ad21bba21b7..fc4f22ca4f480 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -166,7 +166,7 @@ impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { inline::record_extern_fqn(cx, trait_ref.def_id, kind); let path = external_path( cx, - cx.tcx.item_name(trait_ref.def_id), + trait_ref.def_id, Some(trait_ref.def_id), true, bounds.to_vec(), @@ -1448,19 +1448,12 @@ impl<'tcx> Clean for Ty<'tcx> { AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs); + let path = external_path(cx, did, None, false, vec![], substs); ResolvedPath { path, did, is_generic: false } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path( - cx, - cx.tcx.item_name(did), - None, - false, - vec![], - InternalSubsts::empty(), - ); + let path = external_path(cx, did, None, false, vec![], InternalSubsts::empty()); ResolvedPath { path, did, is_generic: false } } ty::Dynamic(ref obj, ref reg) => { @@ -1484,8 +1477,7 @@ impl<'tcx> Clean for Ty<'tcx> { for did in dids { let empty = cx.tcx.intern_substs(&[]); - let path = - external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); + let path = external_path(cx, did, Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); let bound = PolyTrait { trait_: ResolvedPath { path, did, is_generic: false }, @@ -1502,8 +1494,7 @@ impl<'tcx> Clean for Ty<'tcx> { }); } - let path = - external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs); + let path = external_path(cx, did, Some(did), false, bindings, substs); bounds.insert( 0, PolyTrait { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5eff56a2200e1..8d89fae665777 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1158,7 +1158,7 @@ impl GenericBound { crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); + let path = external_path(cx, did, Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( PolyTrait { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a11b9c2af8a96..b6911e8886766 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -141,19 +141,21 @@ fn external_generic_args( } } -// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar -// from Fn<(A, B,), C> to Fn(A, B) -> C +/// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar +/// from `Fn<(A, B,), C>` to `Fn(A, B) -> C` pub(super) fn external_path( cx: &mut DocContext<'_>, - name: Symbol, + did: DefId, trait_did: Option, has_self: bool, bindings: Vec, substs: SubstsRef<'_>, ) -> Path { + let def_kind = cx.tcx.def_kind(did); + let name = cx.tcx.item_name(did); Path { global: false, - res: Res::Err, + res: Res::Def(def_kind, did), segments: vec![PathSegment { name, args: external_generic_args(cx, trait_did, has_self, bindings, substs), diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs index f727c9a47f268..16ab876e829ef 100644 --- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -10,7 +10,7 @@ where // @has no_redundancy/struct.Outer.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl Send for Outer where T: Copy + Send" +// "impl Send for Outer where T: Send + Copy" pub struct Outer { inner_field: Inner, } From c2207f5a48376c7e4ed12975ba1130680cd57455 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 26 Aug 2021 17:47:29 -0700 Subject: [PATCH 29/32] Remove unused `hir_id` parameter from `resolve_type` --- src/librustdoc/clean/mod.rs | 10 +++++----- src/librustdoc/clean/utils.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fc4f22ca4f480..0cd7d5a1ee549 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -906,7 +906,7 @@ impl Clean for hir::IsAuto { impl Clean for hir::TraitRef<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Type { let path = self.path.clean(cx); - resolve_type(cx, path, self.hir_ref_id) + resolve_type(cx, path) } } @@ -1164,7 +1164,7 @@ impl Clean for ty::AssocItem { fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { use rustc_hir::GenericParamCount; - let hir::Ty { hir_id, span, ref kind } = *hir_ty; + let hir::Ty { hir_id: _, span, ref kind } = *hir_ty; let qpath = match kind { hir::TyKind::Path(qpath) => qpath, _ => unreachable!(), @@ -1271,7 +1271,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx)); } let path = path.clean(cx); - resolve_type(cx, path, hir_id) + resolve_type(cx, path) } hir::QPath::Resolved(Some(ref qself), ref p) => { // Try to normalize `::T` to a type @@ -1292,7 +1292,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { name: p.segments.last().expect("segments were empty").ident.name, self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), self_type: Box::new(qself.clean(cx)), - trait_: Box::new(resolve_type(cx, trait_path, hir_id)), + trait_: Box::new(resolve_type(cx, trait_path)), } } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -1308,7 +1308,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { name: segment.ident.name, self_def_id: res.opt_def_id(), self_type: Box::new(qself.clean(cx)), - trait_: Box::new(resolve_type(cx, trait_path, hir_id)), + trait_: Box::new(resolve_type(cx, trait_path)), } } hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"), diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b6911e8886766..64d642884b416 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -407,8 +407,8 @@ crate fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String { } /// Given a type Path, resolve it to a Type using the TyCtxt -crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Type { - debug!("resolve_type({:?},{:?})", path, id); +crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { + debug!("resolve_type({:?})", path); let is_generic = match path.res { Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)), From 5321b35a5ad037369fabae99191c9e45111b21a9 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 11 Sep 2021 15:43:44 -0700 Subject: [PATCH 30/32] Fix redundant arguments in `external_path()` If the path is for a trait, it is always true that `trait_did == Some(did)`, so instead, `external_path()` now takes an `is_trait` boolean. --- src/librustdoc/clean/mod.rs | 18 +++++---------- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/clean/utils.rs | 41 +++++++++++++++++------------------ 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0cd7d5a1ee549..81792ece8a2bb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -164,14 +164,8 @@ impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { ); } inline::record_extern_fqn(cx, trait_ref.def_id, kind); - let path = external_path( - cx, - trait_ref.def_id, - Some(trait_ref.def_id), - true, - bounds.to_vec(), - trait_ref.substs, - ); + let path = + external_path(cx, trait_ref.def_id, true, true, bounds.to_vec(), trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); @@ -1448,12 +1442,12 @@ impl<'tcx> Clean for Ty<'tcx> { AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, did, None, false, vec![], substs); + let path = external_path(cx, did, false, false, vec![], substs); ResolvedPath { path, did, is_generic: false } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path(cx, did, None, false, vec![], InternalSubsts::empty()); + let path = external_path(cx, did, false, false, vec![], InternalSubsts::empty()); ResolvedPath { path, did, is_generic: false } } ty::Dynamic(ref obj, ref reg) => { @@ -1477,7 +1471,7 @@ impl<'tcx> Clean for Ty<'tcx> { for did in dids { let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, Some(did), false, vec![], empty); + let path = external_path(cx, did, true, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); let bound = PolyTrait { trait_: ResolvedPath { path, did, is_generic: false }, @@ -1494,7 +1488,7 @@ impl<'tcx> Clean for Ty<'tcx> { }); } - let path = external_path(cx, did, Some(did), false, bindings, substs); + let path = external_path(cx, did, true, false, bindings, substs); bounds.insert( 0, PolyTrait { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8d89fae665777..0737ff8c6c209 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1158,7 +1158,7 @@ impl GenericBound { crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, Some(did), false, vec![], empty); + let path = external_path(cx, did, true, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( PolyTrait { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 64d642884b416..57ddf81d0e048 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -93,7 +93,8 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { fn external_generic_args( cx: &mut DocContext<'_>, - trait_did: Option, + did: DefId, + is_trait: bool, has_self: bool, bindings: Vec, substs: SubstsRef<'_>, @@ -121,32 +122,30 @@ fn external_generic_args( }) .collect(); - match trait_did { - // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C - Some(did) if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() => { - assert!(ty_kind.is_some()); - let inputs = match ty_kind { - Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), - _ => return GenericArgs::AngleBracketed { args, bindings }, - }; - let output = None; - // FIXME(#20299) return type comes from a projection now - // match types[1].kind { - // ty::Tuple(ref v) if v.is_empty() => None, // -> () - // _ => Some(types[1].clean(cx)) - // }; - GenericArgs::Parenthesized { inputs, output } - } - _ => GenericArgs::AngleBracketed { args, bindings }, + if is_trait && cx.tcx.fn_trait_kind_from_lang_item(did).is_some() { + assert!(ty_kind.is_some()); + let inputs = match ty_kind { + Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), + _ => return GenericArgs::AngleBracketed { args, bindings }, + }; + let output = None; + // FIXME(#20299) return type comes from a projection now + // match types[1].kind { + // ty::Tuple(ref v) if v.is_empty() => None, // -> () + // _ => Some(types[1].clean(cx)) + // }; + GenericArgs::Parenthesized { inputs, output } + } else { + GenericArgs::AngleBracketed { args, bindings } } } -/// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar +/// `is_trait` should be set to `true` if called on a `TraitRef`, in order to sugar /// from `Fn<(A, B,), C>` to `Fn(A, B) -> C` pub(super) fn external_path( cx: &mut DocContext<'_>, did: DefId, - trait_did: Option, + is_trait: bool, has_self: bool, bindings: Vec, substs: SubstsRef<'_>, @@ -158,7 +157,7 @@ pub(super) fn external_path( res: Res::Def(def_kind, did), segments: vec![PathSegment { name, - args: external_generic_args(cx, trait_did, has_self, bindings, substs), + args: external_generic_args(cx, did, is_trait, has_self, bindings, substs), }], } } From 913764dcefb0ba69fcc1dcaa667de01273270331 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 11 Sep 2021 15:55:21 -0700 Subject: [PATCH 31/32] Remove unnecessary `is_trait` argument It was only used for sugaring `Fn` trait bounds, and rustdoc already checks that the `did` is for a `Fn` (or `FnMut`, `FnOnce`) lang item, so it's not necessary to also check that the `did` belongs to a trait. --- src/librustdoc/clean/mod.rs | 11 +++++------ src/librustdoc/clean/types.rs | 2 +- src/librustdoc/clean/utils.rs | 8 ++------ 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 81792ece8a2bb..84ab987062b1f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -164,8 +164,7 @@ impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { ); } inline::record_extern_fqn(cx, trait_ref.def_id, kind); - let path = - external_path(cx, trait_ref.def_id, true, true, bounds.to_vec(), trait_ref.substs); + let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); @@ -1442,12 +1441,12 @@ impl<'tcx> Clean for Ty<'tcx> { AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, did, false, false, vec![], substs); + let path = external_path(cx, did, false, vec![], substs); ResolvedPath { path, did, is_generic: false } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path(cx, did, false, false, vec![], InternalSubsts::empty()); + let path = external_path(cx, did, false, vec![], InternalSubsts::empty()); ResolvedPath { path, did, is_generic: false } } ty::Dynamic(ref obj, ref reg) => { @@ -1471,7 +1470,7 @@ impl<'tcx> Clean for Ty<'tcx> { for did in dids { let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, true, false, vec![], empty); + let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); let bound = PolyTrait { trait_: ResolvedPath { path, did, is_generic: false }, @@ -1488,7 +1487,7 @@ impl<'tcx> Clean for Ty<'tcx> { }); } - let path = external_path(cx, did, true, false, bindings, substs); + let path = external_path(cx, did, false, bindings, substs); bounds.insert( 0, PolyTrait { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0737ff8c6c209..247a6482fdcea 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1158,7 +1158,7 @@ impl GenericBound { crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, true, false, vec![], empty); + let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( PolyTrait { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 57ddf81d0e048..912274c23d6cf 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -94,7 +94,6 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { fn external_generic_args( cx: &mut DocContext<'_>, did: DefId, - is_trait: bool, has_self: bool, bindings: Vec, substs: SubstsRef<'_>, @@ -122,7 +121,7 @@ fn external_generic_args( }) .collect(); - if is_trait && cx.tcx.fn_trait_kind_from_lang_item(did).is_some() { + if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() { assert!(ty_kind.is_some()); let inputs = match ty_kind { Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), @@ -140,12 +139,9 @@ fn external_generic_args( } } -/// `is_trait` should be set to `true` if called on a `TraitRef`, in order to sugar -/// from `Fn<(A, B,), C>` to `Fn(A, B) -> C` pub(super) fn external_path( cx: &mut DocContext<'_>, did: DefId, - is_trait: bool, has_self: bool, bindings: Vec, substs: SubstsRef<'_>, @@ -157,7 +153,7 @@ pub(super) fn external_path( res: Res::Def(def_kind, did), segments: vec![PathSegment { name, - args: external_generic_args(cx, did, is_trait, has_self, bindings, substs), + args: external_generic_args(cx, did, has_self, bindings, substs), }], } } From 280fc2dcce6349beb46b099da8f5fbbf463185cd Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 11 Sep 2021 16:01:49 -0700 Subject: [PATCH 32/32] rustdoc: Cleanup a pattern match in `external_generic_args()` --- src/librustdoc/clean/utils.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 912274c23d6cf..b0021d1234cd6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -122,9 +122,8 @@ fn external_generic_args( .collect(); if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() { - assert!(ty_kind.is_some()); - let inputs = match ty_kind { - Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), + let inputs = match ty_kind.unwrap() { + ty::Tuple(tys) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), _ => return GenericArgs::AngleBracketed { args, bindings }, }; let output = None;