Auto merge of #88881 - Manishearth:rollup-alohfwx, r=Manishearth
Rollup of 7 pull requests Successful merges: - #88336 ( Detect stricter constraints on gats where clauses in impls vs trait) - #88677 (rustc: Remove local variable IDs from `Export`s) - #88699 (Remove extra unshallow from cherry-pick checker) - #88709 (generic_const_exprs: use thir for abstract consts instead of mir) - #88711 (Rework DepthFirstSearch API) - #88810 (rustdoc: Cleanup `clean` part 1) - #88813 (explicitly link to external `ena` docs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c7dbe7a830
67 changed files with 694 additions and 582 deletions
|
@ -83,8 +83,58 @@ impl<G> DepthFirstSearch<'graph, G>
|
||||||
where
|
where
|
||||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
||||||
{
|
{
|
||||||
pub fn new(graph: &'graph G, start_node: G::Node) -> Self {
|
pub fn new(graph: &'graph G) -> Self {
|
||||||
Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
|
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<G> 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,3 +20,19 @@ fn is_cyclic() {
|
||||||
assert!(!is_cyclic(&diamond_acyclic));
|
assert!(!is_cyclic(&diamond_acyclic));
|
||||||
assert!(is_cyclic(&diamond_cyclic));
|
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<usize> = 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));
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ where
|
||||||
where
|
where
|
||||||
Self: WithNumNodes,
|
Self: WithNumNodes,
|
||||||
{
|
{
|
||||||
iterate::DepthFirstSearch::new(self, from)
|
iterate::DepthFirstSearch::new(self).with_start_node(from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#![feature(iter_map_while)]
|
#![feature(iter_map_while)]
|
||||||
#![feature(maybe_uninit_uninit_array)]
|
#![feature(maybe_uninit_uninit_array)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
|
#![feature(never_type)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(new_uninit)]
|
#![feature(new_uninit)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
|
|
|
@ -209,6 +209,12 @@ impl_stable_hash_via_hash!(i128);
|
||||||
impl_stable_hash_via_hash!(char);
|
impl_stable_hash_via_hash!(char);
|
||||||
impl_stable_hash_via_hash!(());
|
impl_stable_hash_via_hash!(());
|
||||||
|
|
||||||
|
impl<CTX> HashStable<CTX> for ! {
|
||||||
|
fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
|
impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
|
||||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||||
self.get().hash_stable(ctx, hasher)
|
self.get().hash_stable(ctx, hasher)
|
||||||
|
|
|
@ -598,6 +598,11 @@ impl<Id> Res<Id> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn expect_non_local<OtherId>(self) -> Res<OtherId> {
|
||||||
|
self.map_id(|_| panic!("unexpected `Res::Local`"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn macro_kind(self) -> Option<MacroKind> {
|
pub fn macro_kind(self) -> Option<MacroKind> {
|
||||||
match self {
|
match self {
|
||||||
Res::Def(DefKind::Macro(kind), _) => Some(kind),
|
Res::Def(DefKind::Macro(kind), _) => Some(kind),
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||||
use crate::infer::{Subtype, ValuePairs};
|
use crate::infer::{SubregionOrigin, Subtype, ValuePairs};
|
||||||
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
|
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -11,12 +11,12 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_middle::ty::error::ExpectedFound;
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::{MultiSpan, Span};
|
use rustc_span::{MultiSpan, Span, Symbol};
|
||||||
|
|
||||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
|
/// 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<ErrorReported> {
|
pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
|
||||||
if let Some(ref error) = self.error {
|
let error = self.error.as_ref()?;
|
||||||
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
|
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
|
||||||
if let RegionResolutionError::SubSupConflict(
|
if let RegionResolutionError::SubSupConflict(
|
||||||
_,
|
_,
|
||||||
|
@ -27,9 +27,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
_sup,
|
_sup,
|
||||||
) = error.clone()
|
) = error.clone()
|
||||||
{
|
{
|
||||||
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) =
|
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
|
||||||
(&sup_origin, &sub_origin)
|
|
||||||
{
|
|
||||||
if let (
|
if let (
|
||||||
ValuePairs::Types(sub_expected_found),
|
ValuePairs::Types(sub_expected_found),
|
||||||
ValuePairs::Types(sup_expected_found),
|
ValuePairs::Types(sup_expected_found),
|
||||||
|
@ -48,6 +46,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
return Some(ErrorReported);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -107,6 +116,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
err.emit();
|
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> {
|
struct TypeParamSpanVisitor<'tcx> {
|
||||||
|
|
|
@ -99,6 +99,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
"...so that the definition in impl matches the definition from the trait",
|
"...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,
|
trait_item_def_id,
|
||||||
&format!("`{}: {}`", sup, sub),
|
&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),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -427,6 +427,15 @@ pub enum SubregionOrigin<'tcx> {
|
||||||
impl_item_def_id: DefId,
|
impl_item_def_id: DefId,
|
||||||
trait_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.
|
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
|
@ -1810,6 +1819,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
||||||
ReferenceOutlivesReferent(_, a) => a,
|
ReferenceOutlivesReferent(_, a) => a,
|
||||||
CallReturn(a) => a,
|
CallReturn(a) => a,
|
||||||
CompareImplMethodObligation { span, .. } => span,
|
CompareImplMethodObligation { span, .. } => span,
|
||||||
|
CompareImplTypeObligation { span, .. } => span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1833,6 +1843,17 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
||||||
trait_item_def_id,
|
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(),
|
_ => default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib};
|
||||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
|
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
|
||||||
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
||||||
use rustc_middle::mir::{self, Body, Promoted};
|
use rustc_middle::mir::{self, Body, Promoted};
|
||||||
|
use rustc_middle::thir;
|
||||||
use rustc_middle::ty::codec::TyDecoder;
|
use rustc_middle::ty::codec::TyDecoder;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
|
use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
|
||||||
use rustc_serialize::{opaque, Decodable, Decoder};
|
use rustc_serialize::{opaque, Decodable, Decoder};
|
||||||
|
@ -541,7 +542,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
|
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
|
||||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
|
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
|
||||||
ty::codec::RefDecodable::decode(d)
|
ty::codec::RefDecodable::decode(d)
|
||||||
}
|
}
|
||||||
|
@ -1020,10 +1021,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over each child of the given item.
|
/// Iterates over each child of the given item.
|
||||||
fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
|
fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) {
|
||||||
where
|
|
||||||
F: FnMut(Export<hir::HirId>),
|
|
||||||
{
|
|
||||||
if let Some(data) = &self.root.proc_macro_data {
|
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
|
/* If we are loading as a proc macro, we want to return the view of this crate
|
||||||
* as a proc macro crate.
|
* as a proc macro crate.
|
||||||
|
@ -1199,14 +1197,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
.decode((self, tcx))
|
.decode((self, tcx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mir_abstract_const(
|
fn get_thir_abstract_const(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
id: DefIndex,
|
id: DefIndex,
|
||||||
) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
||||||
self.root
|
self.root
|
||||||
.tables
|
.tables
|
||||||
.mir_abstract_consts
|
.thir_abstract_consts
|
||||||
.get(self, id)
|
.get(self, id)
|
||||||
.map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
|
.map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::rmeta::encoder;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::stable_map::FxHashMap;
|
use rustc_data_structures::stable_map::FxHashMap;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_hir::def::{CtorKind, DefKind};
|
use rustc_hir::def::{CtorKind, DefKind};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||||
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
|
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
|
||||||
|
@ -117,7 +116,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||||
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
|
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)) }
|
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)) }
|
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) }
|
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)) }
|
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) }
|
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
|
||||||
|
@ -326,8 +325,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
// (restrict scope of mutable-borrow of `visible_parent_map`)
|
// (restrict scope of mutable-borrow of `visible_parent_map`)
|
||||||
{
|
{
|
||||||
let visible_parent_map = &mut visible_parent_map;
|
let visible_parent_map = &mut visible_parent_map;
|
||||||
let mut add_child =
|
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| {
|
||||||
|bfs_queue: &mut VecDeque<_>, child: &Export<hir::HirId>, parent: DefId| {
|
|
||||||
if child.vis != ty::Visibility::Public {
|
if child.vis != ty::Visibility::Public {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -393,11 +391,7 @@ impl CStore {
|
||||||
self.get_crate_data(def.krate).get_visibility(def.index)
|
self.get_crate_data(def.krate).get_visibility(def.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn item_children_untracked(
|
pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<Export> {
|
||||||
&self,
|
|
||||||
def_id: DefId,
|
|
||||||
sess: &Session,
|
|
||||||
) -> Vec<Export<hir::HirId>> {
|
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
self.get_crate_data(def_id.krate).each_child_of_item(
|
self.get_crate_data(def_id.krate).each_child_of_item(
|
||||||
def_id.index,
|
def_id.index,
|
||||||
|
|
|
@ -23,6 +23,7 @@ use rustc_middle::middle::exported_symbols::{
|
||||||
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
|
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
|
||||||
};
|
};
|
||||||
use rustc_middle::mir::interpret;
|
use rustc_middle::mir::interpret;
|
||||||
|
use rustc_middle::thir;
|
||||||
use rustc_middle::traits::specialization_graph;
|
use rustc_middle::traits::specialization_graph;
|
||||||
use rustc_middle::ty::codec::TyEncoder;
|
use rustc_middle::ty::codec::TyEncoder;
|
||||||
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
|
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<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
|
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
|
||||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
|
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
|
||||||
(**self).encode(s)
|
(**self).encode(s)
|
||||||
}
|
}
|
||||||
|
@ -1065,14 +1066,7 @@ impl EncodeContext<'a, 'tcx> {
|
||||||
// items - we encode information about proc-macros later on.
|
// items - we encode information about proc-macros later on.
|
||||||
let reexports = if !self.is_proc_macro {
|
let reexports = if !self.is_proc_macro {
|
||||||
match tcx.module_exports(local_def_id) {
|
match tcx.module_exports(local_def_id) {
|
||||||
Some(exports) => {
|
Some(exports) => self.lazy(exports),
|
||||||
let hir = self.tcx.hir();
|
|
||||||
self.lazy(
|
|
||||||
exports
|
|
||||||
.iter()
|
|
||||||
.map(|export| export.map_id(|id| hir.local_def_id_to_hir_id(id))),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => Lazy::empty(),
|
_ => Lazy::empty(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1304,9 +1298,10 @@ impl EncodeContext<'a, 'tcx> {
|
||||||
if encode_const {
|
if encode_const {
|
||||||
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
|
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(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 {
|
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));
|
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
|
||||||
|
|
|
@ -15,6 +15,7 @@ use rustc_middle::hir::exports::Export;
|
||||||
use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
|
use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
|
||||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
|
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
|
use rustc_middle::thir;
|
||||||
use rustc_middle::ty::{self, ReprOptions, Ty};
|
use rustc_middle::ty::{self, ReprOptions, Ty};
|
||||||
use rustc_serialize::opaque::Encoder;
|
use rustc_serialize::opaque::Encoder;
|
||||||
use rustc_session::config::SymbolManglingVersion;
|
use rustc_session::config::SymbolManglingVersion;
|
||||||
|
@ -305,7 +306,7 @@ define_tables! {
|
||||||
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
||||||
mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
||||||
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
|
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
|
||||||
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
|
thir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
|
||||||
const_defaults: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
|
const_defaults: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
|
||||||
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
|
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
|
||||||
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
||||||
|
@ -359,7 +360,7 @@ struct RenderedConst(String);
|
||||||
|
|
||||||
#[derive(MetadataEncodable, MetadataDecodable)]
|
#[derive(MetadataEncodable, MetadataDecodable)]
|
||||||
struct ModData {
|
struct ModData {
|
||||||
reexports: Lazy<[Export<hir::HirId>]>,
|
reexports: Lazy<[Export]>,
|
||||||
expansion: ExpnId,
|
expansion: ExpnId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,23 +11,18 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
/// This is the replacement export map. It maps a module to all of the exports
|
/// This is the replacement export map. It maps a module to all of the exports
|
||||||
/// within.
|
/// within.
|
||||||
pub type ExportMap<Id> = FxHashMap<LocalDefId, Vec<Export<Id>>>;
|
pub type ExportMap = FxHashMap<LocalDefId, Vec<Export>>;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub struct Export<Id> {
|
pub struct Export {
|
||||||
/// The name of the target.
|
/// The name of the target.
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
/// The resolution of the target.
|
/// The resolution of the target.
|
||||||
pub res: Res<Id>,
|
/// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
|
||||||
|
pub res: Res<!>,
|
||||||
/// The span of the target.
|
/// The span of the target.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The visibility of the export.
|
/// The visibility of the export.
|
||||||
/// We include non-`pub` exports for hygienic macros that get used from extern crates.
|
/// We include non-`pub` exports for hygienic macros that get used from extern crates.
|
||||||
pub vis: ty::Visibility,
|
pub vis: ty::Visibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Id> Export<Id> {
|
|
||||||
pub fn map_id<R>(self, map: impl FnMut(Id) -> R) -> Export<R> {
|
|
||||||
Export { ident: self.ident, res: self.res.map_id(map), span: self.span, vis: self.vis }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
//! A subset of a mir body used for const evaluatability checking.
|
|
||||||
use crate::mir::{self, CastKind};
|
|
||||||
use crate::ty::{self, Ty};
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
|
||||||
/// An index into an `AbstractConst`.
|
|
||||||
pub struct NodeId {
|
|
||||||
derive [HashStable]
|
|
||||||
DEBUG_FORMAT = "n{}",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A node of an `AbstractConst`.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
|
||||||
pub enum Node<'tcx> {
|
|
||||||
Leaf(&'tcx ty::Const<'tcx>),
|
|
||||||
Binop(mir::BinOp, NodeId, NodeId),
|
|
||||||
UnaryOp(mir::UnOp, NodeId),
|
|
||||||
FunctionCall(NodeId, &'tcx [NodeId]),
|
|
||||||
Cast(CastKind, NodeId, Ty<'tcx>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
|
||||||
pub enum NotConstEvaluatable {
|
|
||||||
Error(rustc_errors::ErrorReported),
|
|
||||||
MentionsInfer,
|
|
||||||
MentionsParam,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<rustc_errors::ErrorReported> for NotConstEvaluatable {
|
|
||||||
fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable {
|
|
||||||
NotConstEvaluatable::Error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TrivialTypeFoldableAndLiftImpls! {
|
|
||||||
NotConstEvaluatable,
|
|
||||||
}
|
|
|
@ -40,7 +40,6 @@ use self::graph_cyclic_cache::GraphIsCyclicCache;
|
||||||
use self::predecessors::{PredecessorCache, Predecessors};
|
use self::predecessors::{PredecessorCache, Predecessors};
|
||||||
pub use self::query::*;
|
pub use self::query::*;
|
||||||
|
|
||||||
pub mod abstract_const;
|
|
||||||
pub mod coverage;
|
pub mod coverage;
|
||||||
mod generic_graph;
|
mod generic_graph;
|
||||||
pub mod generic_graphviz;
|
pub mod generic_graphviz;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Values computed by queries that use MIR.
|
//! Values computed by queries that use MIR.
|
||||||
|
|
||||||
use crate::mir::{abstract_const, Body, Promoted};
|
use crate::mir::{Body, Promoted};
|
||||||
use crate::ty::{self, Ty, TyCtxt};
|
use crate::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_data_structures::vec_map::VecMap;
|
use rustc_data_structures::vec_map::VecMap;
|
||||||
|
@ -431,16 +431,4 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.mir_for_ctfe(def.did)
|
self.mir_for_ctfe(def.did)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mir_abstract_const_opt_const_arg(
|
|
||||||
self,
|
|
||||||
def: ty::WithOptConstParam<DefId>,
|
|
||||||
) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> {
|
|
||||||
if let Some((did, param_did)) = def.as_const_arg() {
|
|
||||||
self.mir_abstract_const_of_const_arg((did, param_did))
|
|
||||||
} else {
|
|
||||||
self.mir_abstract_const(def.did)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,17 +303,17 @@ rustc_queries! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to build an abstract representation of the given constant.
|
/// Try to build an abstract representation of the given constant.
|
||||||
query mir_abstract_const(
|
query thir_abstract_const(
|
||||||
key: DefId
|
key: DefId
|
||||||
) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
||||||
desc {
|
desc {
|
||||||
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
|
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Try to build an abstract representation of the given constant.
|
/// 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)
|
key: (LocalDefId, DefId)
|
||||||
) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
||||||
desc {
|
desc {
|
||||||
|tcx|
|
|tcx|
|
||||||
"building an abstract representation for the const argument {}",
|
"building an abstract representation for the const argument {}",
|
||||||
|
@ -1189,7 +1189,7 @@ rustc_queries! {
|
||||||
desc { "traits in scope at a block" }
|
desc { "traits in scope at a block" }
|
||||||
}
|
}
|
||||||
|
|
||||||
query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export<LocalDefId>]> {
|
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()) }
|
desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1401,7 +1401,7 @@ rustc_queries! {
|
||||||
eval_always
|
eval_always
|
||||||
desc { "fetching what a crate is named" }
|
desc { "fetching what a crate is named" }
|
||||||
}
|
}
|
||||||
query item_children(def_id: DefId) -> &'tcx [Export<hir::HirId>] {
|
query item_children(def_id: DefId) -> &'tcx [Export] {
|
||||||
desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
|
||||||
}
|
}
|
||||||
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
|
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
|
||||||
|
|
|
@ -33,6 +33,9 @@ use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
||||||
|
pub mod abstract_const;
|
||||||
|
pub mod visit;
|
||||||
|
|
||||||
newtype_index! {
|
newtype_index! {
|
||||||
/// An index to an [`Arm`] stored in [`Thir::arms`]
|
/// An index to an [`Arm`] stored in [`Thir::arms`]
|
||||||
#[derive(HashStable)]
|
#[derive(HashStable)]
|
||||||
|
|
61
compiler/rustc_middle/src/thir/abstract_const.rs
Normal file
61
compiler/rustc_middle/src/thir/abstract_const.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
//! A subset of a mir body used for const evaluatability checking.
|
||||||
|
use crate::mir;
|
||||||
|
use crate::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_errors::ErrorReported;
|
||||||
|
|
||||||
|
rustc_index::newtype_index! {
|
||||||
|
/// An index into an `AbstractConst`.
|
||||||
|
pub struct NodeId {
|
||||||
|
derive [HashStable]
|
||||||
|
DEBUG_FORMAT = "n{}",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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> {
|
||||||
|
Leaf(&'tcx ty::Const<'tcx>),
|
||||||
|
Binop(mir::BinOp, NodeId, NodeId),
|
||||||
|
UnaryOp(mir::UnOp, NodeId),
|
||||||
|
FunctionCall(NodeId, &'tcx [NodeId]),
|
||||||
|
Cast(CastKind, NodeId, Ty<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||||
|
pub enum NotConstEvaluatable {
|
||||||
|
Error(ErrorReported),
|
||||||
|
MentionsInfer,
|
||||||
|
MentionsParam,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ErrorReported> for NotConstEvaluatable {
|
||||||
|
fn from(e: ErrorReported) -> NotConstEvaluatable {
|
||||||
|
NotConstEvaluatable::Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TrivialTypeFoldableAndLiftImpls! {
|
||||||
|
NotConstEvaluatable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
#[inline]
|
||||||
|
pub fn thir_abstract_const_opt_const_arg(
|
||||||
|
self,
|
||||||
|
def: ty::WithOptConstParam<rustc_hir::def_id::DefId>,
|
||||||
|
) -> Result<Option<&'tcx [Node<'tcx>]>, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
use rustc_middle::thir::{self, *};
|
use super::{
|
||||||
|
Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
|
||||||
|
};
|
||||||
use rustc_middle::ty::Const;
|
use rustc_middle::ty::Const;
|
||||||
|
|
||||||
pub trait Visitor<'a, 'tcx: 'a>: Sized {
|
pub trait Visitor<'a, 'tcx: 'a>: Sized {
|
||||||
|
@ -101,7 +103,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
|
||||||
visitor.visit_expr(&visitor.thir()[field]);
|
visitor.visit_expr(&visitor.thir()[field]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Adt(box thir::Adt {
|
Adt(box crate::thir::Adt {
|
||||||
ref fields,
|
ref fields,
|
||||||
ref base,
|
ref base,
|
||||||
adt_def: _,
|
adt_def: _,
|
|
@ -9,7 +9,7 @@ pub mod specialization_graph;
|
||||||
mod structural_impls;
|
mod structural_impls;
|
||||||
|
|
||||||
use crate::infer::canonical::Canonical;
|
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::subst::SubstsRef;
|
||||||
use crate::ty::{self, AdtKind, Ty, TyCtxt};
|
use crate::ty::{self, AdtKind, Ty, TyCtxt};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use crate::mir::{
|
||||||
self,
|
self,
|
||||||
interpret::{AllocId, Allocation},
|
interpret::{AllocId, Allocation},
|
||||||
};
|
};
|
||||||
|
use crate::thir;
|
||||||
use crate::ty::subst::SubstsRef;
|
use crate::ty::subst::SubstsRef;
|
||||||
use crate::ty::{self, List, Ty, TyCtxt};
|
use crate::ty::{self, List, Ty, TyCtxt};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
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> {
|
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
|
||||||
Ok(decoder.tcx().arena.alloc_from_iter(
|
Ok(decoder.tcx().arena.alloc_from_iter(
|
||||||
(0..decoder.read_usize()?)
|
(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> {
|
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
|
||||||
Ok(decoder.tcx().arena.alloc_from_iter(
|
Ok(decoder.tcx().arena.alloc_from_iter(
|
||||||
(0..decoder.read_usize()?)
|
(0..decoder.read_usize()?)
|
||||||
|
|
|
@ -127,7 +127,7 @@ pub struct ResolverOutputs {
|
||||||
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
||||||
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
|
pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
|
||||||
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
|
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
|
||||||
pub export_map: ExportMap<LocalDefId>,
|
pub export_map: ExportMap,
|
||||||
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
||||||
/// Extern prelude entries. The value is `true` if the entry was introduced
|
/// Extern prelude entries. The value is `true` if the entry was introduced
|
||||||
/// via `extern crate` item and not `--extern` option or compiler built-in.
|
/// via `extern crate` item and not `--extern` option or compiler built-in.
|
||||||
|
|
|
@ -47,10 +47,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||||
// Ensure unsafeck is ran before we steal the THIR.
|
// Ensure unsafeck is ran before we steal the THIR.
|
||||||
match def {
|
match def {
|
||||||
ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
|
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().thir_abstract_const_of_const_arg((did, const_param_did));
|
||||||
}
|
}
|
||||||
ty::WithOptConstParam { did, const_param_did: None } => {
|
ty::WithOptConstParam { did, const_param_did: None } => {
|
||||||
tcx.ensure().thir_check_unsafety(did)
|
tcx.ensure().thir_check_unsafety(did);
|
||||||
|
tcx.ensure().thir_abstract_const(did);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::build::ExprCategory;
|
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_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
|
|
@ -11,4 +11,3 @@ crate mod cx;
|
||||||
crate mod pattern;
|
crate mod pattern;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
pub mod visit;
|
|
||||||
|
|
|
@ -306,7 +306,6 @@ fn mir_promoted(
|
||||||
// this point, before we steal the mir-const result.
|
// this point, before we steal the mir-const result.
|
||||||
// Also this means promotion can rely on all const checks having been done.
|
// 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_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 body = tcx.mir_const(def).steal();
|
||||||
|
|
||||||
let mut required_consts = Vec::new();
|
let mut required_consts = Vec::new();
|
||||||
|
|
|
@ -19,8 +19,8 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
|
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
|
||||||
use rustc_middle::mir::abstract_const::Node as ACNode;
|
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
|
use rustc_middle::thir::abstract_const::Node as ACNode;
|
||||||
use rustc_middle::ty::fold::TypeVisitor;
|
use rustc_middle::ty::fold::TypeVisitor;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||||
|
|
|
@ -9,6 +9,7 @@ use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
|
use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
|
||||||
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
||||||
use rustc_middle::mir::{self, interpret};
|
use rustc_middle::mir::{self, interpret};
|
||||||
|
use rustc_middle::thir;
|
||||||
use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
|
use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_query_system::dep_graph::DepContext;
|
use rustc_query_system::dep_graph::DepContext;
|
||||||
|
@ -921,7 +922,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
|
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
|
||||||
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
|
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
|
||||||
RefDecodable::decode(d)
|
RefDecodable::decode(d)
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,6 @@ impl<'a> Resolver<'a> {
|
||||||
crate fn build_reduced_graph_external(&mut self, module: Module<'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");
|
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) {
|
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);
|
let parent_scope = ParentScope::module(module, self);
|
||||||
BuildReducedGraphVisitor { r: self, parent_scope }
|
BuildReducedGraphVisitor { r: self, parent_scope }
|
||||||
.build_reduced_graph_for_external_crate_res(child);
|
.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.
|
/// Builds the reduced graph for a single item in an external crate.
|
||||||
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
|
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
|
||||||
let parent = self.parent_scope.module;
|
let parent = self.parent_scope.module;
|
||||||
let Export { ident, res, vis, span } = child;
|
let Export { ident, res, vis, span } = child;
|
||||||
|
let res = res.expect_non_local();
|
||||||
let expansion = self.parent_scope.expansion;
|
let expansion = self.parent_scope.expansion;
|
||||||
// Record primary definitions.
|
// Record primary definitions.
|
||||||
match res {
|
match res {
|
||||||
|
|
|
@ -11,7 +11,6 @@ use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBindin
|
||||||
|
|
||||||
use rustc_ast::unwrap_or;
|
use rustc_ast::unwrap_or;
|
||||||
use rustc_ast::NodeId;
|
use rustc_ast::NodeId;
|
||||||
use rustc_ast_lowering::ResolverAstLowering;
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::ptr_key::PtrKey;
|
use rustc_data_structures::ptr_key::PtrKey;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability};
|
use rustc_errors::{pluralize, struct_span_err, Applicability};
|
||||||
|
@ -1387,13 +1386,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
||||||
|
|
||||||
let mut reexports = Vec::new();
|
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.
|
// Filter away ambiguous imports and anything that has def-site hygiene.
|
||||||
// FIXME: Implement actual cross-crate hygiene.
|
// FIXME: Implement actual cross-crate hygiene.
|
||||||
let is_good_import =
|
let is_good_import =
|
||||||
binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
|
binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
|
||||||
if is_good_import || binding.is_macro_def() {
|
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 {
|
if res != def::Res::Err {
|
||||||
reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
|
reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(format_args_capture)]
|
#![feature(format_args_capture)]
|
||||||
#![feature(iter_zip)]
|
#![feature(iter_zip)]
|
||||||
|
#![feature(never_type)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
#![allow(rustdoc::private_intra_doc_links)]
|
#![allow(rustdoc::private_intra_doc_links)]
|
||||||
|
@ -911,7 +912,7 @@ pub struct Resolver<'a> {
|
||||||
|
|
||||||
/// `CrateNum` resolutions of `extern crate` items.
|
/// `CrateNum` resolutions of `extern crate` items.
|
||||||
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
||||||
export_map: ExportMap<LocalDefId>,
|
export_map: ExportMap,
|
||||||
trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
|
trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
|
||||||
|
|
||||||
/// A map from nodes to anonymous modules.
|
/// A map from nodes to anonymous modules.
|
||||||
|
|
|
@ -366,6 +366,18 @@ direct_serialize_impls! {
|
||||||
char emit_char read_char
|
char emit_char read_char
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: Encoder> Encodable<S> for ! {
|
||||||
|
fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Decoder> Decodable<D> for ! {
|
||||||
|
fn decode(_d: &mut D) -> Result<!, D::Error> {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
|
impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
|
||||||
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
|
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
|
||||||
s.emit_u32(self.get())
|
s.emit_u32(self.get())
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
//! this is not as easy.
|
//! this is not as easy.
|
||||||
//!
|
//!
|
||||||
//! In this case we try to build an abstract representation of this constant using
|
//! 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.
|
//! generic constants mentioned in the `caller_bounds` of the current environment.
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_index::bit_set::BitSet;
|
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable};
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
|
use rustc_middle::thir;
|
||||||
|
use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
|
||||||
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
||||||
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
|
@ -196,7 +196,7 @@ impl<'tcx> AbstractConst<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
uv: ty::Unevaluated<'tcx, ()>,
|
uv: ty::Unevaluated<'tcx, ()>,
|
||||||
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
|
) -> Result<Option<AbstractConst<'tcx>>, 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);
|
debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
|
||||||
Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
|
Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
|
||||||
}
|
}
|
||||||
|
@ -223,35 +223,24 @@ impl<'tcx> AbstractConst<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
struct WorkNode<'tcx> {
|
|
||||||
node: Node<'tcx>,
|
|
||||||
span: Span,
|
|
||||||
used: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AbstractConstBuilder<'a, 'tcx> {
|
struct AbstractConstBuilder<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &'a mir::Body<'tcx>,
|
body_id: thir::ExprId,
|
||||||
|
body: &'a thir::Thir<'tcx>,
|
||||||
/// The current WIP node tree.
|
/// The current WIP node tree.
|
||||||
///
|
nodes: IndexVec<NodeId, Node<'tcx>>,
|
||||||
/// 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<NodeId, WorkNode<'tcx>>,
|
|
||||||
locals: IndexVec<mir::Local, NodeId>,
|
|
||||||
/// We only allow field accesses if they access
|
|
||||||
/// the result of a checked operation.
|
|
||||||
checked_op_locals: BitSet<mir::Local>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
|
fn root_span(&self) -> Span {
|
||||||
|
self.body.exprs[self.body_id].span
|
||||||
|
}
|
||||||
|
|
||||||
fn error(&mut self, span: Option<Span>, msg: &str) -> Result<!, ErrorReported> {
|
fn error(&mut self, span: Option<Span>, msg: &str) -> Result<!, ErrorReported> {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(self.body.span, "overly complex generic constant")
|
.struct_span_err(self.root_span(), "overly complex generic constant")
|
||||||
.span_label(span.unwrap_or(self.body.span), msg)
|
.span_label(span.unwrap_or(self.root_span()), msg)
|
||||||
.help("consider moving this anonymous constant into a `const` function")
|
.help("consider moving this anonymous constant into a `const` function")
|
||||||
.emit();
|
.emit();
|
||||||
|
|
||||||
|
@ -260,100 +249,51 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &'a mir::Body<'tcx>,
|
(body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId),
|
||||||
) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorReported> {
|
) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorReported> {
|
||||||
let mut builder = AbstractConstBuilder {
|
let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() };
|
||||||
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
|
struct IsThirPolymorphic<'a, 'tcx> {
|
||||||
// can just evaluate them.
|
is_poly: bool,
|
||||||
if !body.is_polymorphic {
|
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 == 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
|
||||||
|
if is_poly_vis.is_poly == false {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(builder))
|
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 })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn place_to_local(
|
|
||||||
&mut self,
|
|
||||||
span: Span,
|
|
||||||
p: &mir::Place<'tcx>,
|
|
||||||
) -> Result<mir::Local, ErrorReported> {
|
|
||||||
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<NodeId, ErrorReported> {
|
|
||||||
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.
|
/// We do not allow all binary operations in abstract consts, so filter disallowed ones.
|
||||||
fn check_binop(op: mir::BinOp) -> bool {
|
fn check_binop(op: mir::BinOp) -> bool {
|
||||||
use mir::BinOp::*;
|
use mir::BinOp::*;
|
||||||
|
@ -373,170 +313,126 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> {
|
/// Builds the abstract const by walking the thir and bailing out when
|
||||||
debug!("AbstractConstBuilder: stmt={:?}", stmt);
|
/// encountering an unspported operation.
|
||||||
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<Option<mir::BasicBlock>, 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::<Result<Vec<NodeId>, _>>()?,
|
|
||||||
);
|
|
||||||
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.
|
|
||||||
fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> {
|
fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> {
|
||||||
let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
|
debug!("Abstractconstbuilder::build: body={:?}", &*self.body);
|
||||||
// We checked for a cyclic cfg above, so this should terminate.
|
self.recurse_build(self.body_id)?;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
|
|
||||||
for n in self.nodes.iter() {
|
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
|
// `AbstractConst`s should not contain any promoteds as they require references which
|
||||||
// are not allowed.
|
// are not allowed.
|
||||||
assert_eq!(ct.promoted, None);
|
assert_eq!(ct.promoted, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.nodes[self.locals[mir::RETURN_PLACE]].used = true;
|
Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter()))
|
||||||
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<NodeId, ErrorReported> {
|
||||||
|
use thir::ExprKind;
|
||||||
|
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
|
||||||
|
&ExprKind::Scope { value, .. } => self.recurse_build(value)?,
|
||||||
|
&ExprKind::PlaceTypeAscription { source, .. } |
|
||||||
|
&ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
|
||||||
|
|
||||||
|
// subtle: associated consts are literals this arm handles
|
||||||
|
// `<T as Trait>::ASSOC` as well as `12`
|
||||||
|
&ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)),
|
||||||
|
|
||||||
|
ExprKind::Call { fun, args, .. } => {
|
||||||
|
let fun = self.recurse_build(*fun)?;
|
||||||
|
|
||||||
|
let mut new_args = Vec::<NodeId>::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.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.nodes.push(Node::Binop(op, lhs, rhs))
|
||||||
|
}
|
||||||
|
&ExprKind::Unary { op, arg } if Self::check_unop(op) => {
|
||||||
|
let arg = self.recurse_build(arg)?;
|
||||||
|
self.nodes.push(Node::UnaryOp(op, arg))
|
||||||
|
},
|
||||||
|
// This is necessary so that the following compiles:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// fn foo<const N: usize>(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`. (untested)
|
||||||
|
&ExprKind::Use { source } => {
|
||||||
|
let arg = self.recurse_build(source)?;
|
||||||
|
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.
|
||||||
|
ExprKind::AddressOf { .. }
|
||||||
|
| ExprKind::Borrow { .. }
|
||||||
|
| ExprKind::Deref { .. }
|
||||||
|
| ExprKind::Repeat { .. }
|
||||||
|
| ExprKind::Array { .. }
|
||||||
|
| ExprKind::Block { .. }
|
||||||
|
| ExprKind::NeverToAny { .. }
|
||||||
|
| ExprKind::Tuple { .. }
|
||||||
|
| ExprKind::Index { .. }
|
||||||
|
| ExprKind::Field { .. }
|
||||||
|
| ExprKind::ConstBlock { .. }
|
||||||
|
| ExprKind::Adt(_) => self.error(
|
||||||
|
Some(node.span),
|
||||||
|
"unsupported operation in generic constant, this may be supported in the future",
|
||||||
|
)?,
|
||||||
|
|
||||||
|
ExprKind::Match { .. }
|
||||||
|
// 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 { .. }
|
||||||
|
// we handle valid unary/binary ops above
|
||||||
|
| ExprKind::Unary { .. }
|
||||||
|
| ExprKind::Binary { .. }
|
||||||
|
| ExprKind::Break { .. }
|
||||||
|
| ExprKind::Continue { .. }
|
||||||
|
| ExprKind::If { .. }
|
||||||
|
| 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 { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
|
/// 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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def: ty::WithOptConstParam<LocalDefId>,
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
|
||||||
if tcx.features().generic_const_exprs {
|
if tcx.features().generic_const_exprs {
|
||||||
match tcx.def_kind(def.did) {
|
match tcx.def_kind(def.did) {
|
||||||
// FIXME(generic_const_exprs): We currently only do this for anonymous constants,
|
// FIXME(generic_const_exprs): We currently only do this for anonymous constants,
|
||||||
|
@ -547,8 +443,16 @@ pub(super) fn mir_abstract_const<'tcx>(
|
||||||
DefKind::AnonConst => (),
|
DefKind::AnonConst => (),
|
||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
}
|
}
|
||||||
let body = tcx.mir_const(def).borrow();
|
|
||||||
AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose()
|
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 {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -682,11 +586,16 @@ pub(super) fn try_unify<'tcx>(
|
||||||
&& iter::zip(a_args, b_args)
|
&& iter::zip(a_args, b_args)
|
||||||
.all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
|
.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))
|
(Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
|
||||||
if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
|
if (a_ty == b_ty) && (a_kind == b_kind) =>
|
||||||
{
|
{
|
||||||
try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
|
try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
|
||||||
}
|
}
|
||||||
_ => false,
|
// use this over `_ => false` to make adding variants to `Node` less error prone
|
||||||
|
(Node::Cast(..), _)
|
||||||
|
| (Node::FunctionCall(..), _)
|
||||||
|
| (Node::UnaryOp(..), _)
|
||||||
|
| (Node::Binop(..), _)
|
||||||
|
| (Node::Leaf(..), _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::GenericParam;
|
use rustc_hir::GenericParam;
|
||||||
use rustc_hir::Item;
|
use rustc_hir::Item;
|
||||||
use rustc_hir::Node;
|
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::error::ExpectedFound;
|
||||||
use rustc_middle::ty::fold::TypeFolder;
|
use rustc_middle::ty::fold::TypeFolder;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
|
|
|
@ -5,8 +5,8 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
|
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::mir::interpret::ErrorHandled;
|
||||||
|
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::ToPredicate;
|
use rustc_middle::ty::ToPredicate;
|
||||||
|
|
|
@ -827,16 +827,16 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
vtable_entries,
|
vtable_entries,
|
||||||
vtable_trait_upcasting_coercion_new_vptr_slot,
|
vtable_trait_upcasting_coercion_new_vptr_slot,
|
||||||
subst_and_check_impossible_predicates,
|
subst_and_check_impossible_predicates,
|
||||||
mir_abstract_const: |tcx, def_id| {
|
thir_abstract_const: |tcx, def_id| {
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
|
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 {
|
} 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)| {
|
thir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
|
||||||
const_evaluatable::mir_abstract_const(
|
const_evaluatable::thir_abstract_const(
|
||||||
tcx,
|
tcx,
|
||||||
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
|
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
// This shouldn't really matter though as we can't really use any
|
||||||
// constants which are not considered const evaluatable.
|
// 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()) {
|
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
|
||||||
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
|
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
|
||||||
Node::Leaf(leaf) => {
|
Node::Leaf(leaf) => {
|
||||||
|
|
|
@ -34,8 +34,8 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||||
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
|
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
|
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
||||||
use rustc_middle::ty::fast_reject;
|
use rustc_middle::ty::fast_reject;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::relate::TypeRelation;
|
use rustc_middle::ty::relate::TypeRelation;
|
||||||
|
|
|
@ -1655,7 +1655,7 @@ fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] {
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
traits: &mut Vec<DefId>,
|
traits: &mut Vec<DefId>,
|
||||||
external_mods: &mut FxHashSet<DefId>,
|
external_mods: &mut FxHashSet<DefId>,
|
||||||
res: Res,
|
res: Res<!>,
|
||||||
) {
|
) {
|
||||||
match res {
|
match res {
|
||||||
Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
|
Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
|
||||||
|
|
|
@ -590,10 +590,18 @@ impl Step for Rustc {
|
||||||
cargo.rustdocflag("-Znormalize-docs");
|
cargo.rustdocflag("-Znormalize-docs");
|
||||||
cargo.rustdocflag("--show-type-layout");
|
cargo.rustdocflag("--show-type-layout");
|
||||||
compile::rustc_cargo(builder, &mut cargo, target);
|
compile::rustc_cargo(builder, &mut cargo, target);
|
||||||
|
cargo.arg("-Zunstable-options");
|
||||||
cargo.arg("-Zskip-rustdoc-fingerprint");
|
cargo.arg("-Zskip-rustdoc-fingerprint");
|
||||||
|
|
||||||
// Only include compiler crates, no dependencies of those, such as `libc`.
|
// 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("--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.
|
// Find dependencies for top level crates.
|
||||||
let mut compiler_crates = HashSet::new();
|
let mut compiler_crates = HashSet::new();
|
||||||
|
|
|
@ -18,14 +18,6 @@ verify_backported_commits_main() {
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
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
|
if [[ $ci_base_branch == "beta" ]]; then
|
||||||
verify_cherries master "$BETA_LIMIT" \
|
verify_cherries master "$BETA_LIMIT" \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
|
@ -482,12 +482,13 @@ fn build_module(
|
||||||
// visit each node at most once.
|
// visit each node at most once.
|
||||||
for &item in cx.tcx.item_children(did).iter() {
|
for &item in cx.tcx.item_children(did).iter() {
|
||||||
if item.vis == ty::Visibility::Public {
|
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) {
|
if did == def_id || !visited.insert(def_id) {
|
||||||
continue;
|
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.
|
// Primitive types can't be inlined so generate an import instead.
|
||||||
let prim_ty = clean::PrimitiveType::from(p);
|
let prim_ty = clean::PrimitiveType::from(p);
|
||||||
items.push(clean::Item {
|
items.push(clean::Item {
|
||||||
|
@ -500,7 +501,7 @@ fn build_module(
|
||||||
clean::ImportSource {
|
clean::ImportSource {
|
||||||
path: clean::Path {
|
path: clean::Path {
|
||||||
global: false,
|
global: false,
|
||||||
res: item.res,
|
res,
|
||||||
segments: vec![clean::PathSegment {
|
segments: vec![clean::PathSegment {
|
||||||
name: prim_ty.as_sym(),
|
name: prim_ty.as_sym(),
|
||||||
args: clean::GenericArgs::AngleBracketed {
|
args: clean::GenericArgs::AngleBracketed {
|
||||||
|
@ -515,9 +516,7 @@ fn build_module(
|
||||||
))),
|
))),
|
||||||
cfg: None,
|
cfg: None,
|
||||||
});
|
});
|
||||||
} else if let Some(i) =
|
} else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) {
|
||||||
try_inline(cx, did, None, item.res, item.ident.name, None, visited)
|
|
||||||
{
|
|
||||||
items.extend(i)
|
items.extend(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,14 +164,7 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
inline::record_extern_fqn(cx, trait_ref.def_id, kind);
|
inline::record_extern_fqn(cx, trait_ref.def_id, kind);
|
||||||
let path = external_path(
|
let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs);
|
||||||
cx,
|
|
||||||
cx.tcx.item_name(trait_ref.def_id),
|
|
||||||
Some(trait_ref.def_id),
|
|
||||||
true,
|
|
||||||
bounds.to_vec(),
|
|
||||||
trait_ref.substs,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
|
debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
|
||||||
|
|
||||||
|
@ -906,7 +899,7 @@ impl Clean<bool> for hir::IsAuto {
|
||||||
impl Clean<Type> for hir::TraitRef<'_> {
|
impl Clean<Type> for hir::TraitRef<'_> {
|
||||||
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
|
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
|
||||||
let path = self.path.clean(cx);
|
let path = self.path.clean(cx);
|
||||||
resolve_type(cx, path, self.hir_ref_id)
|
resolve_type(cx, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,7 +1157,7 @@ impl Clean<Item> for ty::AssocItem {
|
||||||
|
|
||||||
fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
||||||
use rustc_hir::GenericParamCount;
|
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 {
|
let qpath = match kind {
|
||||||
hir::TyKind::Path(qpath) => qpath,
|
hir::TyKind::Path(qpath) => qpath,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -1271,7 +1264,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));
|
return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
|
||||||
}
|
}
|
||||||
let path = path.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) => {
|
hir::QPath::Resolved(Some(ref qself), ref p) => {
|
||||||
// Try to normalize `<X as Y>::T` to a type
|
// Try to normalize `<X as Y>::T` to a type
|
||||||
|
@ -1292,7 +1285,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
||||||
name: p.segments.last().expect("segments were empty").ident.name,
|
name: p.segments.last().expect("segments were empty").ident.name,
|
||||||
self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
|
self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
|
||||||
self_type: Box::new(qself.clean(cx)),
|
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) => {
|
hir::QPath::TypeRelative(ref qself, ref segment) => {
|
||||||
|
@ -1308,7 +1301,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
||||||
name: segment.ident.name,
|
name: segment.ident.name,
|
||||||
self_def_id: res.opt_def_id(),
|
self_def_id: res.opt_def_id(),
|
||||||
self_type: Box::new(qself.clean(cx)),
|
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"),
|
hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
|
||||||
|
@ -1448,19 +1441,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||||
AdtKind::Enum => ItemType::Enum,
|
AdtKind::Enum => ItemType::Enum,
|
||||||
};
|
};
|
||||||
inline::record_extern_fqn(cx, did, kind);
|
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, false, vec![], substs);
|
||||||
ResolvedPath { path, did, is_generic: false }
|
ResolvedPath { path, did, is_generic: false }
|
||||||
}
|
}
|
||||||
ty::Foreign(did) => {
|
ty::Foreign(did) => {
|
||||||
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
|
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
|
||||||
let path = external_path(
|
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
|
||||||
cx,
|
|
||||||
cx.tcx.item_name(did),
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
vec![],
|
|
||||||
InternalSubsts::empty(),
|
|
||||||
);
|
|
||||||
ResolvedPath { path, did, is_generic: false }
|
ResolvedPath { path, did, is_generic: false }
|
||||||
}
|
}
|
||||||
ty::Dynamic(ref obj, ref reg) => {
|
ty::Dynamic(ref obj, ref reg) => {
|
||||||
|
@ -1484,8 +1470,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||||
|
|
||||||
for did in dids {
|
for did in dids {
|
||||||
let empty = cx.tcx.intern_substs(&[]);
|
let empty = cx.tcx.intern_substs(&[]);
|
||||||
let path =
|
let path = external_path(cx, did, false, vec![], empty);
|
||||||
external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
|
|
||||||
inline::record_extern_fqn(cx, did, ItemType::Trait);
|
inline::record_extern_fqn(cx, did, ItemType::Trait);
|
||||||
let bound = PolyTrait {
|
let bound = PolyTrait {
|
||||||
trait_: ResolvedPath { path, did, is_generic: false },
|
trait_: ResolvedPath { path, did, is_generic: false },
|
||||||
|
@ -1502,8 +1487,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let path =
|
let path = external_path(cx, did, false, bindings, substs);
|
||||||
external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs);
|
|
||||||
bounds.insert(
|
bounds.insert(
|
||||||
0,
|
0,
|
||||||
PolyTrait {
|
PolyTrait {
|
||||||
|
|
|
@ -212,7 +212,7 @@ impl ExternalCrate {
|
||||||
crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
|
crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
|
||||||
let root = self.def_id();
|
let root = self.def_id();
|
||||||
|
|
||||||
let as_keyword = |res: Res| {
|
let as_keyword = |res: Res<!>| {
|
||||||
if let Res::Def(DefKind::Mod, def_id) = res {
|
if let Res::Def(DefKind::Mod, def_id) = res {
|
||||||
let attrs = tcx.get_attrs(def_id);
|
let attrs = tcx.get_attrs(def_id);
|
||||||
let mut keyword = None;
|
let mut keyword = None;
|
||||||
|
@ -243,7 +243,8 @@ impl ExternalCrate {
|
||||||
hir::ItemKind::Use(ref path, hir::UseKind::Single)
|
hir::ItemKind::Use(ref path, hir::UseKind::Single)
|
||||||
if item.vis.node.is_pub() =>
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -274,7 +275,7 @@ impl ExternalCrate {
|
||||||
// Also note that this does not attempt to deal with modules tagged
|
// Also note that this does not attempt to deal with modules tagged
|
||||||
// duplicately for the same primitive. This is handled later on when
|
// duplicately for the same primitive. This is handled later on when
|
||||||
// rendering by delegating everything to a hash map.
|
// 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 {
|
if let Res::Def(DefKind::Mod, def_id) = res {
|
||||||
let attrs = tcx.get_attrs(def_id);
|
let attrs = tcx.get_attrs(def_id);
|
||||||
let mut prim = None;
|
let mut prim = None;
|
||||||
|
@ -309,7 +310,7 @@ impl ExternalCrate {
|
||||||
hir::ItemKind::Use(ref path, hir::UseKind::Single)
|
hir::ItemKind::Use(ref path, hir::UseKind::Single)
|
||||||
if item.vis.node.is_pub() =>
|
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.
|
// Pretend the primitive is local.
|
||||||
(id.def_id.to_def_id(), prim)
|
(id.def_id.to_def_id(), prim)
|
||||||
})
|
})
|
||||||
|
@ -1110,7 +1111,7 @@ impl GenericBound {
|
||||||
crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
|
crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
|
||||||
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
|
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
|
||||||
let empty = cx.tcx.intern_substs(&[]);
|
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, false, vec![], empty);
|
||||||
inline::record_extern_fqn(cx, did, ItemType::Trait);
|
inline::record_extern_fqn(cx, did, ItemType::Trait);
|
||||||
GenericBound::TraitBound(
|
GenericBound::TraitBound(
|
||||||
PolyTrait {
|
PolyTrait {
|
||||||
|
|
|
@ -29,10 +29,6 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
|
||||||
let krate = cx.tcx.hir().krate();
|
let krate = cx.tcx.hir().krate();
|
||||||
let module = crate::visit_ast::RustdocVisitor::new(cx).visit(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();
|
let mut externs = Vec::new();
|
||||||
for &cnum in cx.tcx.crates(()).iter() {
|
for &cnum in cx.tcx.crates(()).iter() {
|
||||||
externs.push(ExternalCrate { crate_num: cnum });
|
externs.push(ExternalCrate { crate_num: cnum });
|
||||||
|
@ -97,7 +93,7 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
|
||||||
|
|
||||||
fn external_generic_args(
|
fn external_generic_args(
|
||||||
cx: &mut DocContext<'_>,
|
cx: &mut DocContext<'_>,
|
||||||
trait_did: Option<DefId>,
|
did: DefId,
|
||||||
has_self: bool,
|
has_self: bool,
|
||||||
bindings: Vec<TypeBinding>,
|
bindings: Vec<TypeBinding>,
|
||||||
substs: SubstsRef<'_>,
|
substs: SubstsRef<'_>,
|
||||||
|
@ -125,12 +121,9 @@ fn external_generic_args(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
match trait_did {
|
if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
|
||||||
// Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
|
let inputs = match ty_kind.unwrap() {
|
||||||
Some(did) if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() => {
|
ty::Tuple(tys) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
|
||||||
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 },
|
_ => return GenericArgs::AngleBracketed { args, bindings },
|
||||||
};
|
};
|
||||||
let output = None;
|
let output = None;
|
||||||
|
@ -140,27 +133,26 @@ fn external_generic_args(
|
||||||
// _ => Some(types[1].clean(cx))
|
// _ => Some(types[1].clean(cx))
|
||||||
// };
|
// };
|
||||||
GenericArgs::Parenthesized { inputs, output }
|
GenericArgs::Parenthesized { inputs, output }
|
||||||
}
|
} else {
|
||||||
_ => GenericArgs::AngleBracketed { args, bindings },
|
GenericArgs::AngleBracketed { args, bindings }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(
|
pub(super) fn external_path(
|
||||||
cx: &mut DocContext<'_>,
|
cx: &mut DocContext<'_>,
|
||||||
name: Symbol,
|
did: DefId,
|
||||||
trait_did: Option<DefId>,
|
|
||||||
has_self: bool,
|
has_self: bool,
|
||||||
bindings: Vec<TypeBinding>,
|
bindings: Vec<TypeBinding>,
|
||||||
substs: SubstsRef<'_>,
|
substs: SubstsRef<'_>,
|
||||||
) -> Path {
|
) -> Path {
|
||||||
|
let def_kind = cx.tcx.def_kind(did);
|
||||||
|
let name = cx.tcx.item_name(did);
|
||||||
Path {
|
Path {
|
||||||
global: false,
|
global: false,
|
||||||
res: Res::Err,
|
res: Res::Def(def_kind, did),
|
||||||
segments: vec![PathSegment {
|
segments: vec![PathSegment {
|
||||||
name,
|
name,
|
||||||
args: external_generic_args(cx, trait_did, has_self, bindings, substs),
|
args: external_generic_args(cx, did, has_self, bindings, substs),
|
||||||
}],
|
}],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,8 +401,8 @@ crate fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a type Path, resolve it to a Type using the TyCtxt
|
/// 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 {
|
crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
|
||||||
debug!("resolve_type({:?},{:?})", path, id);
|
debug!("resolve_type({:?})", path);
|
||||||
|
|
||||||
let is_generic = match path.res {
|
let is_generic = match path.res {
|
||||||
Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)),
|
Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)),
|
||||||
|
@ -418,7 +410,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty
|
||||||
return Generic(kw::SelfUpper);
|
return Generic(kw::SelfUpper);
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
|
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,
|
Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -98,9 +98,6 @@ crate struct Cache {
|
||||||
stripped_mod: bool,
|
stripped_mod: bool,
|
||||||
|
|
||||||
crate search_index: Vec<IndexItem>,
|
crate search_index: Vec<IndexItem>,
|
||||||
crate deref_trait_did: Option<DefId>,
|
|
||||||
crate deref_mut_trait_did: Option<DefId>,
|
|
||||||
crate owned_box_did: Option<DefId>,
|
|
||||||
|
|
||||||
// In rare case where a structure is defined in one module but implemented
|
// In rare case where a structure is defined in one module but implemented
|
||||||
// in another, if the implementing module is parsed before defining module,
|
// in another, if the implementing module is parsed before defining module,
|
||||||
|
|
|
@ -51,6 +51,7 @@ use rustc_hir::def::CtorKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::Mutability;
|
use rustc_hir::Mutability;
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
use serde::ser::SerializeSeq;
|
use serde::ser::SerializeSeq;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
|
@ -1067,13 +1068,13 @@ fn render_assoc_items(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !traits.is_empty() {
|
if !traits.is_empty() {
|
||||||
let deref_impl = traits
|
let deref_impl = traits.iter().find(|t| {
|
||||||
.iter()
|
t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
|
||||||
.find(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did);
|
});
|
||||||
if let Some(impl_) = deref_impl {
|
if let Some(impl_) = deref_impl {
|
||||||
let has_deref_mut = traits
|
let has_deref_mut = traits.iter().any(|t| {
|
||||||
.iter()
|
t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_mut_trait()
|
||||||
.any(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_mut_trait_did);
|
});
|
||||||
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
|
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
|
||||||
}
|
}
|
||||||
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
|
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
|
||||||
|
@ -1163,7 +1164,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, tcx: TyCtxt<'_>) -> bool {
|
||||||
let self_type_opt = match *item.kind {
|
let self_type_opt = match *item.kind {
|
||||||
clean::MethodItem(ref method, _) => method.decl.self_type(),
|
clean::MethodItem(ref method, _) => method.decl.self_type(),
|
||||||
clean::TyMethodItem(ref method) => method.decl.self_type(),
|
clean::TyMethodItem(ref method) => method.decl.self_type(),
|
||||||
|
@ -1177,7 +1178,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bo
|
||||||
(mutability == Mutability::Mut, false, false)
|
(mutability == Mutability::Mut, false, false)
|
||||||
}
|
}
|
||||||
SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
|
SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
|
||||||
(false, Some(did) == cache.owned_box_did, false)
|
(false, Some(did) == tcx.lang_items().owned_box(), false)
|
||||||
}
|
}
|
||||||
SelfTy::SelfValue => (false, false, true),
|
SelfTy::SelfValue => (false, false, true),
|
||||||
_ => (false, false, false),
|
_ => (false, false, false),
|
||||||
|
@ -1300,7 +1301,7 @@ fn render_impl(
|
||||||
&& match render_mode {
|
&& match render_mode {
|
||||||
RenderMode::Normal => true,
|
RenderMode::Normal => true,
|
||||||
RenderMode::ForDeref { mut_: deref_mut_ } => {
|
RenderMode::ForDeref { mut_: deref_mut_ } => {
|
||||||
should_render_item(&item, deref_mut_, cx.cache())
|
should_render_item(&item, deref_mut_, cx.tcx())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1798,13 +1799,13 @@ fn get_methods(
|
||||||
for_deref: bool,
|
for_deref: bool,
|
||||||
used_links: &mut FxHashSet<String>,
|
used_links: &mut FxHashSet<String>,
|
||||||
deref_mut: bool,
|
deref_mut: bool,
|
||||||
cache: &Cache,
|
tcx: TyCtxt<'_>,
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
i.items
|
i.items
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|item| match item.name {
|
.filter_map(|item| match item.name {
|
||||||
Some(ref name) if !name.is_empty() && item.is_method() => {
|
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, tcx) {
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"<a href=\"#{}\">{}</a>",
|
"<a href=\"#{}\">{}</a>",
|
||||||
get_next_url(used_links, format!("method.{}", name)),
|
get_next_url(used_links, format!("method.{}", name)),
|
||||||
|
@ -1866,7 +1867,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
|
||||||
let mut ret = v
|
let mut ret = v
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|i| i.inner_impl().trait_.is_none())
|
.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.tcx())
|
||||||
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if !ret.is_empty() {
|
if !ret.is_empty() {
|
||||||
// We want links' order to be reproducible so we don't use unstable sort.
|
// We want links' order to be reproducible so we don't use unstable sort.
|
||||||
|
@ -1884,11 +1887,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 v.iter().any(|i| i.inner_impl().trait_.is_some()) {
|
||||||
if let Some(impl_) = v
|
if let Some(impl_) = v.iter().filter(|i| i.inner_impl().trait_.is_some()).find(|i| {
|
||||||
.iter()
|
i.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
|
||||||
.filter(|i| i.inner_impl().trait_.is_some())
|
}) {
|
||||||
.find(|i| i.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did)
|
|
||||||
{
|
|
||||||
sidebar_deref_methods(cx, out, impl_, v);
|
sidebar_deref_methods(cx, out, impl_, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1986,10 +1987,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let deref_mut = v
|
let deref_mut = v.iter().filter(|i| i.inner_impl().trait_.is_some()).any(|i| {
|
||||||
.iter()
|
i.inner_impl().trait_.def_id_full(c) == cx.tcx().lang_items().deref_mut_trait()
|
||||||
.filter(|i| i.inner_impl().trait_.is_some())
|
});
|
||||||
.any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did);
|
|
||||||
let inner_impl = target
|
let inner_impl = target
|
||||||
.def_id_full(c)
|
.def_id_full(c)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
@ -2002,7 +2002,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
|
||||||
let mut ret = impls
|
let mut ret = impls
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|i| i.inner_impl().trait_.is_none())
|
.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.tcx())
|
||||||
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if !ret.is_empty() {
|
if !ret.is_empty() {
|
||||||
write!(
|
write!(
|
||||||
|
|
|
@ -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 def_id = res.def_id();
|
||||||
let vis = self.tcx.visibility(def_id);
|
let vis = self.tcx.visibility(def_id);
|
||||||
let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None };
|
let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None };
|
||||||
|
|
|
@ -10,7 +10,7 @@ where
|
||||||
|
|
||||||
// @has no_redundancy/struct.Outer.html
|
// @has no_redundancy/struct.Outer.html
|
||||||
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
|
// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
|
||||||
// "impl<T> Send for Outer<T> where T: Copy + Send"
|
// "impl<T> Send for Outer<T> where T: Send + Copy"
|
||||||
pub struct Outer<T> {
|
pub struct Outer<T> {
|
||||||
inner_field: Inner<T>,
|
inner_field: Inner<T>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
fn foo<const N: u8>(a: [(); N as usize]) {
|
||||||
|
bar::<{ N as usize as usize }>();
|
||||||
|
//~^ error: unconstrained generic constant
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar<const N: usize>() {}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -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
|
||||||
|
|
|
@ -10,7 +10,7 @@ error: overly complex generic constant
|
||||||
--> $DIR/array-size-in-generic-struct-param.rs:19:15
|
--> $DIR/array-size-in-generic-struct-param.rs:19:15
|
||||||
|
|
|
|
||||||
LL | arr: [u8; CFG.arr_size],
|
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
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ error: overly complex generic constant
|
||||||
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
|
LL | fn test<const N: usize>() -> [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
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ error: overly complex generic constant
|
||||||
--> $DIR/let-bindings.rs:6:68
|
--> $DIR/let-bindings.rs:6:68
|
||||||
|
|
|
|
||||||
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
|
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
|
||||||
| ^^^^^^-^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
|
||||||
| |
|
|
||||||
| unsupported statement
|
|
||||||
|
|
|
|
||||||
= help: consider moving this anonymous constant into a `const` function
|
= 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
|
--> $DIR/let-bindings.rs:6:35
|
||||||
|
|
|
|
||||||
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
|
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
|
||||||
| ^^^^^^-^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
|
||||||
| |
|
|
||||||
| unsupported statement
|
|
||||||
|
|
|
|
||||||
= help: consider moving this anonymous constant into a `const` function
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
#![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);
|
||||||
|
|
||||||
|
impl const std::ops::Add for Foo {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Evaluatable<const N: Foo>;
|
||||||
|
|
||||||
|
fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
|
||||||
|
bar::<{ std::ops::Add::add(N, N) }>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar<const N: Foo>() {}
|
||||||
|
|
||||||
|
// test that `N + N` unifies with explicit function calls for builin-types
|
||||||
|
struct Evaluatable2<const N: usize>;
|
||||||
|
|
||||||
|
fn foo2<const N: usize>(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<const N: usize>() {}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -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
|
||||||
|
|
|
@ -2,9 +2,7 @@ error: overly complex generic constant
|
||||||
--> $DIR/unused_expr.rs:4:34
|
--> $DIR/unused_expr.rs:4:34
|
||||||
|
|
|
|
||||||
LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
|
LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
|
||||||
| ^^-----^^^^^
|
| ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
|
||||||
| |
|
|
||||||
| dead code
|
|
||||||
|
|
|
|
||||||
= help: consider moving this anonymous constant into a `const` function
|
= 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
|
--> $DIR/unused_expr.rs:9:34
|
||||||
|
|
|
|
||||||
LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
|
LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
|
||||||
| ^^-----^^^^^
|
| ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
|
||||||
| |
|
|
||||||
| dead code
|
|
||||||
|
|
|
|
||||||
= help: consider moving this anonymous constant into a `const` function
|
= 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
|
--> $DIR/unused_expr.rs:16:38
|
||||||
|
|
|
|
||||||
LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
|
LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
|
||||||
| ^^------^^^^^
|
| ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
|
||||||
| |
|
|
||||||
| dead code
|
|
||||||
|
|
|
|
||||||
= help: consider moving this anonymous constant into a `const` function
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ error: overly complex generic constant
|
||||||
--> $DIR/issue-67375.rs:7:17
|
--> $DIR/issue-67375.rs:7:17
|
||||||
|
|
|
|
||||||
LL | inner: [(); { [|_: &T| {}; 0].len() }],
|
LL | inner: [(); { [|_: &T| {}; 0].len() }],
|
||||||
| ^^^----------^^^^^^^^^^^^
|
| ^^---------------^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| unsupported rvalue
|
| unsupported operation in generic constant
|
||||||
|
|
|
|
||||||
= help: consider moving this anonymous constant into a `const` function
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,10 @@ LL | A: [(); {
|
||||||
| _____________^
|
| _____________^
|
||||||
LL | |
|
LL | |
|
||||||
LL | | let x: Option<Box<Self>> = None;
|
LL | | let x: Option<Box<Self>> = None;
|
||||||
| | ---- unsupported rvalue
|
|
||||||
LL | |
|
LL | |
|
||||||
LL | | 0
|
LL | | 0
|
||||||
LL | | }],
|
LL | | }],
|
||||||
| |_____^
|
| |_____^ unsupported operation in generic constant, this may be supported in the future
|
||||||
|
|
|
|
||||||
= help: consider moving this anonymous constant into a `const` function
|
= help: consider moving this anonymous constant into a `const` function
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ impl<T> Foo for Fooy<T> {
|
||||||
type A<'a> where Self: 'static = (&'a ());
|
type A<'a> where Self: 'static = (&'a ());
|
||||||
//~^ ERROR the parameter type `T` may not live long enough
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
||||||
//~^ ERROR lifetime bound not satisfied
|
//~^ ERROR `impl` associated type
|
||||||
//~| ERROR lifetime bound not satisfied
|
//~| ERROR lifetime bound not satisfied
|
||||||
type C where Self: Copy = String;
|
type C where Self: Copy = String;
|
||||||
//~^ ERROR the trait bound `T: Copy` is not satisfied
|
//~^ ERROR the trait bound `T: Copy` is not satisfied
|
||||||
|
|
|
@ -5,24 +5,16 @@ LL | type A<'a> where Self: 'static = (&'a ());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider adding an explicit lifetime bound `T: 'static`...
|
= help: consider adding an explicit lifetime bound `T: 'static`...
|
||||||
= note: ...so that the type `Fooy<T>` 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
|
--> $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 ());
|
LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
|
||||||
|
|
|
||||||
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
|
|
||||||
|
|
|
||||||
LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
|
|
||||||
| ^^
|
|
||||||
|
|
||||||
error[E0478]: lifetime bound not satisfied
|
error[E0478]: lifetime bound not satisfied
|
||||||
--> $DIR/impl_bounds.rs:17:5
|
--> $DIR/impl_bounds.rs:17:5
|
||||||
|
|
|
@ -9,7 +9,7 @@ LL | | <Left as HasChildrenOf>::T: 'a,
|
||||||
LL | | <Right as HasChildrenOf>::T: 'a
|
LL | | <Right as HasChildrenOf>::T: 'a
|
||||||
| | - help: consider adding a where clause: `, <Left as HasChildrenOf>::T: 'a`
|
| | - help: consider adding a where clause: `, <Left as HasChildrenOf>::T: 'a`
|
||||||
LL | | = Either<&'a Left::T, &'a Right::T>;
|
LL | | = Either<&'a Left::T, &'a Right::T>;
|
||||||
| |________________________________________^ ...so that the type `<Left as HasChildrenOf>::T` will meet its required lifetime bounds
|
| |________________________________________^ ...so that the definition in impl matches the definition from the trait
|
||||||
|
|
||||||
error[E0309]: the associated type `<Right as HasChildrenOf>::T` may not live long enough
|
error[E0309]: the associated type `<Right as HasChildrenOf>::T` may not live long enough
|
||||||
--> $DIR/issue-86787.rs:23:5
|
--> $DIR/issue-86787.rs:23:5
|
||||||
|
@ -22,7 +22,7 @@ LL | | <Left as HasChildrenOf>::T: 'a,
|
||||||
LL | | <Right as HasChildrenOf>::T: 'a
|
LL | | <Right as HasChildrenOf>::T: 'a
|
||||||
| | - help: consider adding a where clause: `, <Right as HasChildrenOf>::T: 'a`
|
| | - help: consider adding a where clause: `, <Right as HasChildrenOf>::T: 'a`
|
||||||
LL | | = Either<&'a Left::T, &'a Right::T>;
|
LL | | = Either<&'a Left::T, &'a Right::T>;
|
||||||
| |________________________________________^ ...so that the type `<Right as HasChildrenOf>::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
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,11 @@
|
||||||
|
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: aborting due to previous error
|
||||||
|
|
|
@ -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<HirId>> {
|
fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> {
|
||||||
tcx.item_children(def_id)
|
tcx.item_children(def_id)
|
||||||
.iter()
|
.iter()
|
||||||
.find(|item| item.ident.name.as_str() == name)
|
.find(|item| item.ident.name.as_str() == name)
|
||||||
|
@ -557,7 +557,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
try_res!(last).res
|
try_res!(last).res.expect_non_local()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function to get the `DefId` of a trait by path.
|
/// Convenience function to get the `DefId` of a trait by path.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue