Auto merge of #68078 - Centril:rollup-qvq052k, r=Centril
Rollup of 6 pull requests Successful merges: - #66463 (Point at opaque and closure type definitions in type errors) - #67501 (Reduce special treatment for zsts) - #67820 (Parse the syntax described in RFC 2632) - #67922 (rustc_ast_lowering: misc cleanup & rustc dep reductions) - #68071 (Extend support of `_` in type parameters) - #68073 (expect `fn` after `const unsafe` / `const extern`) Failed merges: r? @ghost
This commit is contained in:
commit
2d8d559bbe
97 changed files with 2076 additions and 1042 deletions
|
@ -22,7 +22,7 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
|||
use crate::ty::fold::TypeFoldable;
|
||||
use crate::ty::subst::{GenericArg, GenericArgKind};
|
||||
use crate::ty::{self, BoundVar, Ty, TyCtxt};
|
||||
use crate::util::captures::Captures;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
|
|
@ -68,9 +68,12 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::Node;
|
||||
|
||||
use errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString};
|
||||
use errors::{
|
||||
pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_error_codes::*;
|
||||
use rustc_span::{Pos, Span};
|
||||
use rustc_span::{DesugaringKind, Pos, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::{cmp, fmt};
|
||||
|
||||
|
@ -1289,6 +1292,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
mut values: Option<ValuePairs<'tcx>>,
|
||||
terr: &TypeError<'tcx>,
|
||||
) {
|
||||
let span = cause.span(self.tcx);
|
||||
|
||||
// For some types of errors, expected-found does not make
|
||||
// sense, so just ignore the values we were given.
|
||||
match terr {
|
||||
|
@ -1298,6 +1303,100 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
struct OpaqueTypesVisitor<'tcx> {
|
||||
types: FxHashMap<TyCategory, FxHashSet<Span>>,
|
||||
expected: FxHashMap<TyCategory, FxHashSet<Span>>,
|
||||
found: FxHashMap<TyCategory, FxHashSet<Span>>,
|
||||
ignore_span: Span,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueTypesVisitor<'tcx> {
|
||||
fn visit_expected_found(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
ignore_span: Span,
|
||||
) -> Self {
|
||||
let mut types_visitor = OpaqueTypesVisitor {
|
||||
types: Default::default(),
|
||||
expected: Default::default(),
|
||||
found: Default::default(),
|
||||
ignore_span,
|
||||
tcx,
|
||||
};
|
||||
// The visitor puts all the relevant encountered types in `self.types`, but in
|
||||
// here we want to visit two separate types with no relation to each other, so we
|
||||
// move the results from `types` to `expected` or `found` as appropriate.
|
||||
expected.visit_with(&mut types_visitor);
|
||||
std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types);
|
||||
found.visit_with(&mut types_visitor);
|
||||
std::mem::swap(&mut types_visitor.found, &mut types_visitor.types);
|
||||
types_visitor
|
||||
}
|
||||
|
||||
fn report(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
self.add_labels_for_types(err, "expected", &self.expected);
|
||||
self.add_labels_for_types(err, "found", &self.found);
|
||||
}
|
||||
|
||||
fn add_labels_for_types(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
target: &str,
|
||||
types: &FxHashMap<TyCategory, FxHashSet<Span>>,
|
||||
) {
|
||||
for (key, values) in types.iter() {
|
||||
let count = values.len();
|
||||
let kind = key.descr();
|
||||
for sp in values {
|
||||
err.span_label(
|
||||
*sp,
|
||||
format!(
|
||||
"{}{}{} {}{}",
|
||||
if sp.is_desugaring(DesugaringKind::Async) {
|
||||
"the `Output` of this `async fn`'s "
|
||||
} else if count == 1 {
|
||||
"the "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if count > 1 { "one of the " } else { "" },
|
||||
target,
|
||||
kind,
|
||||
pluralize!(count),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
if let Some((kind, def_id)) = TyCategory::from_ty(t) {
|
||||
let span = self.tcx.def_span(def_id);
|
||||
// Avoid cluttering the output when the "found" and error span overlap:
|
||||
//
|
||||
// error[E0308]: mismatched types
|
||||
// --> $DIR/issue-20862.rs:2:5
|
||||
// |
|
||||
// LL | |y| x + y
|
||||
// | ^^^^^^^^^
|
||||
// | |
|
||||
// | the found closure
|
||||
// | expected `()`, found closure
|
||||
// |
|
||||
// = note: expected unit type `()`
|
||||
// found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]`
|
||||
if !self.ignore_span.overlaps(span) {
|
||||
self.types.entry(kind).or_default().insert(span);
|
||||
}
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
debug!("note_type_err(diag={:?})", diag);
|
||||
let (expected_found, exp_found, is_simple_error) = match values {
|
||||
None => (None, None, false),
|
||||
|
@ -1306,6 +1405,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
ValuePairs::Types(exp_found) => {
|
||||
let is_simple_err =
|
||||
exp_found.expected.is_simple_text() && exp_found.found.is_simple_text();
|
||||
OpaqueTypesVisitor::visit_expected_found(
|
||||
self.tcx,
|
||||
exp_found.expected,
|
||||
exp_found.found,
|
||||
span,
|
||||
)
|
||||
.report(diag);
|
||||
|
||||
(is_simple_err, Some(exp_found))
|
||||
}
|
||||
|
@ -1323,8 +1429,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let span = cause.span(self.tcx);
|
||||
|
||||
// Ignore msg for object safe coercion
|
||||
// since E0038 message will be printed
|
||||
match terr {
|
||||
|
@ -1336,7 +1440,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some((expected, found)) = expected_found {
|
||||
let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
|
||||
let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());
|
||||
|
@ -1933,3 +2036,34 @@ impl<'tcx> ObligationCause<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
|
||||
/// extra information about each type, but we only care about the category.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
crate enum TyCategory {
|
||||
Closure,
|
||||
Opaque,
|
||||
Generator,
|
||||
Foreign,
|
||||
}
|
||||
|
||||
impl TyCategory {
|
||||
fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Closure => "closure",
|
||||
Self::Opaque => "opaque type",
|
||||
Self::Generator => "generator",
|
||||
Self::Foreign => "foreign type",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
|
||||
match ty.kind {
|
||||
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
|
||||
ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
|
||||
ty::Generator(def_id, ..) => Some((Self::Generator, def_id)),
|
||||
ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::infer::{GenericKind, VerifyBound};
|
|||
use crate::traits;
|
||||
use crate::ty::subst::{InternalSubsts, Subst};
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::util::captures::Captures;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
|
||||
|
|
|
@ -100,7 +100,6 @@ pub mod ty;
|
|||
|
||||
pub mod util {
|
||||
pub mod bug;
|
||||
pub mod captures;
|
||||
pub mod common;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
use crate::hir::map as hir_map;
|
||||
use crate::hir::map::definitions::{DefKey, DefPathTable};
|
||||
use crate::session::search_paths::PathKind;
|
||||
use crate::session::{CrateDisambiguator, Session};
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::session::CrateDisambiguator;
|
||||
use crate::ty::TyCtxt;
|
||||
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::{self, MetadataRef};
|
||||
|
@ -208,7 +208,6 @@ pub trait CrateStore {
|
|||
fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
|
||||
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
|
||||
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
|
||||
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
|
||||
|
||||
// This is basically a 1-based range of ints, which is a little
|
||||
// silly - I may fix that.
|
||||
|
|
|
@ -6,7 +6,7 @@ use super::{
|
|||
TraitNotObjectSafe,
|
||||
};
|
||||
|
||||
use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode;
|
||||
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{self, InferCtxt};
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
|
@ -446,7 +446,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
flags.push((sym::from_method, Some(method.to_string())));
|
||||
}
|
||||
}
|
||||
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
|
||||
if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
|
||||
flags.push((sym::parent_trait, Some(t)));
|
||||
}
|
||||
|
||||
|
@ -665,13 +665,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Gets the parent trait chain start
|
||||
fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option<String> {
|
||||
fn get_parent_trait_ref(
|
||||
&self,
|
||||
code: &ObligationCauseCode<'tcx>,
|
||||
) -> Option<(String, Option<Span>)> {
|
||||
match code {
|
||||
&ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
|
||||
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
|
||||
match self.get_parent_trait_ref(&data.parent_code) {
|
||||
Some(t) => Some(t),
|
||||
None => Some(parent_trait_ref.skip_binder().self_ty().to_string()),
|
||||
None => {
|
||||
let ty = parent_trait_ref.skip_binder().self_ty();
|
||||
let span =
|
||||
TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
|
||||
Some((ty.to_string(), span))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
|
@ -719,9 +727,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||
let (post_message, pre_message) = self
|
||||
let (post_message, pre_message, type_def) = self
|
||||
.get_parent_trait_ref(&obligation.cause.code)
|
||||
.map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
|
||||
.map(|(t, s)| {
|
||||
(
|
||||
format!(" in `{}`", t),
|
||||
format!("within `{}`, ", t),
|
||||
s.map(|s| (format!("within this `{}`", t), s)),
|
||||
)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let OnUnimplementedNote { message, label, note, enclosing_scope } =
|
||||
|
@ -795,6 +809,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
err.span_label(span, explanation);
|
||||
}
|
||||
if let Some((msg, span)) = type_def {
|
||||
err.span_label(span, &msg);
|
||||
}
|
||||
if let Some(ref s) = note {
|
||||
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
|
||||
err.note(s.as_str());
|
||||
|
|
|
@ -17,7 +17,6 @@ use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
|||
use crate::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use crate::ty::subst::{InternalSubsts, Subst};
|
||||
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
|
||||
use crate::util::common::FN_OUTPUT_NAME;
|
||||
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::HashStable;
|
||||
|
@ -1364,7 +1363,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
|||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
Ident::with_dummy_span(FN_OUTPUT_NAME),
|
||||
Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME),
|
||||
),
|
||||
ty: ret_type,
|
||||
});
|
||||
|
|
|
@ -26,8 +26,8 @@ use crate::ty::layout::VariantIdx;
|
|||
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||
use crate::ty::util::{Discr, IntTypeExt};
|
||||
use crate::ty::walk::TypeWalker;
|
||||
use crate::util::captures::Captures;
|
||||
use arena::SyncDroplessArena;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
|
|
|
@ -13,11 +13,10 @@ use crate::ty::layout::VariantIdx;
|
|||
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||
use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
|
||||
use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS};
|
||||
use crate::util::captures::Captures;
|
||||
use polonius_engine::Atom;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
use polonius_engine::Atom;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
|
|
|
@ -5,14 +5,9 @@ use rustc_data_structures::sync::Lock;
|
|||
use std::fmt::Debug;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// The name of the associated type for `Fn` return types.
|
||||
pub const FN_OUTPUT_NAME: Symbol = sym::Output;
|
||||
|
||||
pub use errors::ErrorReported;
|
||||
|
||||
pub fn to_readable_str(mut val: usize) -> String {
|
||||
|
|
|
@ -25,19 +25,16 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
|
|||
pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
|
||||
}
|
||||
|
||||
impl<'a, 'lowering, 'hir> ItemLowerer<'a, 'lowering, 'hir> {
|
||||
fn with_trait_impl_ref<F>(&mut self, trait_impl_ref: &Option<TraitRef>, f: F)
|
||||
where
|
||||
F: FnOnce(&mut Self),
|
||||
{
|
||||
impl ItemLowerer<'_, '_, '_> {
|
||||
fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
|
||||
let old = self.lctx.is_in_trait_impl;
|
||||
self.lctx.is_in_trait_impl = if let &None = trait_impl_ref { false } else { true };
|
||||
self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true };
|
||||
f(self);
|
||||
self.lctx.is_in_trait_impl = old;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'lowering, 'hir> Visitor<'a> for ItemLowerer<'a, 'lowering, 'hir> {
|
||||
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
|
||||
fn visit_mod(&mut self, m: &'a Mod, _s: Span, _attrs: &[Attribute], n: NodeId) {
|
||||
let hir_id = self.lctx.lower_node_id(n);
|
||||
|
||||
|
@ -71,6 +68,12 @@ impl<'a, 'lowering, 'hir> Visitor<'a> for ItemLowerer<'a, 'lowering, 'hir> {
|
|||
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
|
||||
let this = &mut ItemLowerer { lctx: this };
|
||||
if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.kind {
|
||||
if opt_trait_ref.as_ref().map(|tr| tr.constness.is_some()).unwrap_or(false) {
|
||||
this.lctx
|
||||
.diagnostic()
|
||||
.span_err(item.span, "const trait impls are not yet implemented");
|
||||
}
|
||||
|
||||
this.with_trait_impl_ref(opt_trait_ref, |this| visit::walk_item(this, item));
|
||||
} else {
|
||||
visit::walk_item(this, item);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-tidy-filelength
|
||||
|
||||
//! Lowers the AST to the HIR.
|
||||
//!
|
||||
//! Since the AST and HIR are fairly similar, this is mostly a simple procedure,
|
||||
|
@ -33,21 +31,20 @@
|
|||
//! in the HIR, especially for multiple identifiers.
|
||||
|
||||
#![feature(array_value_iter)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
|
||||
use rustc::arena::Arena;
|
||||
use rustc::dep_graph::DepGraph;
|
||||
use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions};
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint;
|
||||
use rustc::lint::builtin::{self, ELIDED_LIFETIMES_IN_PATHS};
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc::util::captures::Captures;
|
||||
use rustc::util::common::FN_OUTPUT_NAME;
|
||||
use rustc::lint::builtin;
|
||||
use rustc::{bug, span_bug};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_error_codes::*;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{DefId, DefIdMap, DefIndex, CRATE_DEF_INDEX};
|
||||
|
@ -58,14 +55,13 @@ use rustc_session::config::nightly_options;
|
|||
use rustc_session::node_id::NodeMap;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::ExpnId;
|
||||
use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind, Spanned};
|
||||
use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use syntax::ast;
|
||||
use syntax::ast::*;
|
||||
use syntax::attr;
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P as AstP;
|
||||
use syntax::sess::ParseSess;
|
||||
use syntax::token::{self, Nonterminal, Token};
|
||||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
|
@ -86,6 +82,8 @@ macro_rules! arena_vec {
|
|||
|
||||
mod expr;
|
||||
mod item;
|
||||
mod pat;
|
||||
mod path;
|
||||
|
||||
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
|
||||
|
||||
|
@ -173,7 +171,9 @@ struct LoweringContext<'a, 'hir: 'a> {
|
|||
}
|
||||
|
||||
pub trait Resolver {
|
||||
fn cstore(&self) -> &dyn CrateStore;
|
||||
fn def_key(&mut self, id: DefId) -> DefKey;
|
||||
|
||||
fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize;
|
||||
|
||||
/// Obtains resolution for a `NodeId` with a single resolution.
|
||||
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
|
||||
|
@ -433,10 +433,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn with_hir_id_owner<F, T>(&mut self, owner: Option<NodeId>, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_hir_id_owner<T>(
|
||||
&mut self,
|
||||
owner: Option<NodeId>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
let old = mem::replace(&mut self.hir_id_owner, owner);
|
||||
let r = f(self);
|
||||
self.hir_id_owner = old;
|
||||
|
@ -444,7 +445,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, 'lowering, 'hir> Visitor<'tcx> for MiscCollector<'tcx, 'lowering, 'hir> {
|
||||
impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> {
|
||||
fn visit_pat(&mut self, p: &'tcx Pat) {
|
||||
if let PatKind::Paren(..) | PatKind::Rest = p.kind {
|
||||
// Doesn't generate a HIR node
|
||||
|
@ -577,10 +578,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
lowered
|
||||
}
|
||||
|
||||
fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> hir::HirId
|
||||
where
|
||||
F: FnOnce(&mut Self) -> hir::HirId,
|
||||
{
|
||||
fn lower_node_id_generic(
|
||||
&mut self,
|
||||
ast_node_id: NodeId,
|
||||
alloc_hir_id: impl FnOnce(&mut Self) -> hir::HirId,
|
||||
) -> hir::HirId {
|
||||
if ast_node_id == DUMMY_NODE_ID {
|
||||
return hir::DUMMY_HIR_ID;
|
||||
}
|
||||
|
@ -604,10 +606,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_hir_id_owner<T>(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let counter = self
|
||||
.item_local_id_counters
|
||||
.insert(owner, HIR_ID_COUNTER_LOCKED)
|
||||
|
@ -736,15 +735,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
/// Presuming that in-band lifetimes are enabled, then
|
||||
/// `self.anonymous_lifetime_mode` will be updated to match the
|
||||
/// parameter while `f` is running (and restored afterwards).
|
||||
fn collect_in_band_defs<T, F>(
|
||||
fn collect_in_band_defs<T>(
|
||||
&mut self,
|
||||
parent_id: DefId,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode,
|
||||
f: F,
|
||||
) -> (Vec<hir::GenericParam<'hir>>, T)
|
||||
where
|
||||
F: FnOnce(&mut Self) -> (Vec<hir::GenericParam<'hir>>, T),
|
||||
{
|
||||
f: impl FnOnce(&mut Self) -> (Vec<hir::GenericParam<'hir>>, T),
|
||||
) -> (Vec<hir::GenericParam<'hir>>, T) {
|
||||
assert!(!self.is_collecting_in_band_lifetimes);
|
||||
assert!(self.lifetimes_to_define.is_empty());
|
||||
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
|
||||
|
@ -847,10 +843,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// This is used to track which lifetimes have already been defined, and
|
||||
// which are new in-band lifetimes that need to have a definition created
|
||||
// for them.
|
||||
fn with_in_scope_lifetime_defs<T, F>(&mut self, params: &[GenericParam], f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_in_scope_lifetime_defs<T>(
|
||||
&mut self,
|
||||
params: &[GenericParam],
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
let old_len = self.in_scope_lifetimes.len();
|
||||
let lt_def_names = params.iter().filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())),
|
||||
|
@ -870,16 +867,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
/// Presuming that in-band lifetimes are enabled, then
|
||||
/// `self.anonymous_lifetime_mode` will be updated to match the
|
||||
/// parameter while `f` is running (and restored afterwards).
|
||||
fn add_in_band_defs<F, T>(
|
||||
fn add_in_band_defs<T>(
|
||||
&mut self,
|
||||
generics: &Generics,
|
||||
parent_id: DefId,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode,
|
||||
f: F,
|
||||
) -> (hir::Generics<'hir>, T)
|
||||
where
|
||||
F: FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
|
||||
{
|
||||
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
|
||||
) -> (hir::Generics<'hir>, T) {
|
||||
let (in_band_defs, (mut lowered_generics, res)) =
|
||||
self.with_in_scope_lifetime_defs(&generics.params, |this| {
|
||||
this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
|
||||
|
@ -917,10 +911,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
(lowered_generics, res)
|
||||
}
|
||||
|
||||
fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let was_in_dyn_type = self.is_in_dyn_type;
|
||||
self.is_in_dyn_type = in_scope;
|
||||
|
||||
|
@ -931,10 +922,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
result
|
||||
}
|
||||
|
||||
fn with_new_scopes<T, F>(&mut self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_new_scopes<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let was_in_loop_condition = self.is_in_loop_condition;
|
||||
self.is_in_loop_condition = false;
|
||||
|
||||
|
@ -949,14 +937,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ret
|
||||
}
|
||||
|
||||
fn def_key(&mut self, id: DefId) -> DefKey {
|
||||
if id.is_local() {
|
||||
self.resolver.definitions().def_key(id.index)
|
||||
} else {
|
||||
self.resolver.cstore().def_key(id)
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_attrs(&mut self, attrs: &[Attribute]) -> &'hir [Attribute] {
|
||||
self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)))
|
||||
}
|
||||
|
@ -1635,403 +1615,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
)
|
||||
}
|
||||
|
||||
fn lower_qpath(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
qself: &Option<QSelf>,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
|
||||
|
||||
let partial_res =
|
||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
|
||||
let proj_start = p.segments.len() - partial_res.unresolved_segments();
|
||||
let path = self.arena.alloc(hir::Path {
|
||||
res: self.lower_res(partial_res.base_res()),
|
||||
segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
|
||||
|(i, segment)| {
|
||||
let param_mode = match (qself_position, param_mode) {
|
||||
(Some(j), ParamMode::Optional) if i < j => {
|
||||
// This segment is part of the trait path in a
|
||||
// qualified path - one of `a`, `b` or `Trait`
|
||||
// in `<X as a::b::Trait>::T::U::method`.
|
||||
ParamMode::Explicit
|
||||
}
|
||||
_ => param_mode,
|
||||
};
|
||||
|
||||
// Figure out if this is a type/trait segment,
|
||||
// which may need lifetime elision performed.
|
||||
let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
|
||||
krate: def_id.krate,
|
||||
index: this.def_key(def_id).parent.expect("missing parent"),
|
||||
};
|
||||
let type_def_id = match partial_res.base_res() {
|
||||
Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
|
||||
Some(parent_def_id(self, def_id))
|
||||
}
|
||||
Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
|
||||
Some(parent_def_id(self, def_id))
|
||||
}
|
||||
Res::Def(DefKind::Struct, def_id)
|
||||
| Res::Def(DefKind::Union, def_id)
|
||||
| Res::Def(DefKind::Enum, def_id)
|
||||
| Res::Def(DefKind::TyAlias, def_id)
|
||||
| Res::Def(DefKind::Trait, def_id)
|
||||
if i + 1 == proj_start =>
|
||||
{
|
||||
Some(def_id)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let parenthesized_generic_args = match partial_res.base_res() {
|
||||
// `a::b::Trait(Args)`
|
||||
Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
|
||||
ParenthesizedGenericArgs::Ok
|
||||
}
|
||||
// `a::b::Trait(Args)::TraitItem`
|
||||
Res::Def(DefKind::Method, _)
|
||||
| Res::Def(DefKind::AssocConst, _)
|
||||
| Res::Def(DefKind::AssocTy, _)
|
||||
if i + 2 == proj_start =>
|
||||
{
|
||||
ParenthesizedGenericArgs::Ok
|
||||
}
|
||||
// Avoid duplicated errors.
|
||||
Res::Err => ParenthesizedGenericArgs::Ok,
|
||||
// An error
|
||||
_ => ParenthesizedGenericArgs::Err,
|
||||
};
|
||||
|
||||
let num_lifetimes = type_def_id.map_or(0, |def_id| {
|
||||
if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
|
||||
return n;
|
||||
}
|
||||
assert!(!def_id.is_local());
|
||||
let item_generics = self
|
||||
.resolver
|
||||
.cstore()
|
||||
.item_generics_cloned_untracked(def_id, self.sess);
|
||||
let n = item_generics.own_counts().lifetimes;
|
||||
self.type_def_lifetime_params.insert(def_id, n);
|
||||
n
|
||||
});
|
||||
self.lower_path_segment(
|
||||
p.span,
|
||||
segment,
|
||||
param_mode,
|
||||
num_lifetimes,
|
||||
parenthesized_generic_args,
|
||||
itctx.reborrow(),
|
||||
None,
|
||||
)
|
||||
},
|
||||
)),
|
||||
span: p.span,
|
||||
});
|
||||
|
||||
// Simple case, either no projections, or only fully-qualified.
|
||||
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
|
||||
if partial_res.unresolved_segments() == 0 {
|
||||
return hir::QPath::Resolved(qself, path);
|
||||
}
|
||||
|
||||
// Create the innermost type that we're projecting from.
|
||||
let mut ty = if path.segments.is_empty() {
|
||||
// If the base path is empty that means there exists a
|
||||
// syntactical `Self`, e.g., `&i32` in `<&i32>::clone`.
|
||||
qself.expect("missing QSelf for <T>::...")
|
||||
} else {
|
||||
// Otherwise, the base path is an implicit `Self` type path,
|
||||
// e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in
|
||||
// `<I as Iterator>::Item::default`.
|
||||
let new_id = self.next_id();
|
||||
self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)))
|
||||
};
|
||||
|
||||
// Anything after the base path are associated "extensions",
|
||||
// out of which all but the last one are associated types,
|
||||
// e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`:
|
||||
// * base path is `std::vec::Vec<T>`
|
||||
// * "extensions" are `IntoIter`, `Item` and `clone`
|
||||
// * type nodes are:
|
||||
// 1. `std::vec::Vec<T>` (created above)
|
||||
// 2. `<std::vec::Vec<T>>::IntoIter`
|
||||
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
|
||||
// * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
|
||||
for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
|
||||
let segment = self.arena.alloc(self.lower_path_segment(
|
||||
p.span,
|
||||
segment,
|
||||
param_mode,
|
||||
0,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
itctx.reborrow(),
|
||||
None,
|
||||
));
|
||||
let qpath = hir::QPath::TypeRelative(ty, segment);
|
||||
|
||||
// It's finished, return the extension of the right node type.
|
||||
if i == p.segments.len() - 1 {
|
||||
return qpath;
|
||||
}
|
||||
|
||||
// Wrap the associated extension in another type node.
|
||||
let new_id = self.next_id();
|
||||
ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath));
|
||||
}
|
||||
|
||||
// We should've returned in the for loop above.
|
||||
span_bug!(
|
||||
p.span,
|
||||
"lower_qpath: no final extension segment in {}..{}",
|
||||
proj_start,
|
||||
p.segments.len()
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_path_extra(
|
||||
&mut self,
|
||||
res: Res,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
explicit_owner: Option<NodeId>,
|
||||
) -> &'hir hir::Path<'hir> {
|
||||
self.arena.alloc(hir::Path {
|
||||
res,
|
||||
segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
|
||||
self.lower_path_segment(
|
||||
p.span,
|
||||
segment,
|
||||
param_mode,
|
||||
0,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::disallowed(),
|
||||
explicit_owner,
|
||||
)
|
||||
})),
|
||||
span: p.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> &'hir hir::Path<'hir> {
|
||||
let res = self.expect_full_res(id);
|
||||
let res = self.lower_res(res);
|
||||
self.lower_path_extra(res, p, param_mode, None)
|
||||
}
|
||||
|
||||
fn lower_path_segment(
|
||||
&mut self,
|
||||
path_span: Span,
|
||||
segment: &PathSegment,
|
||||
param_mode: ParamMode,
|
||||
expected_lifetimes: usize,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: ImplTraitContext<'_, 'hir>,
|
||||
explicit_owner: Option<NodeId>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
|
||||
let msg = "parenthesized type parameters may only be used with a `Fn` trait";
|
||||
match **generic_args {
|
||||
GenericArgs::AngleBracketed(ref data) => {
|
||||
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
|
||||
}
|
||||
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
|
||||
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
|
||||
ParenthesizedGenericArgs::Err => {
|
||||
let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
|
||||
err.span_label(data.span, "only `Fn` traits may use parentheses");
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
|
||||
// Do not suggest going from `Trait()` to `Trait<>`
|
||||
if data.inputs.len() > 0 {
|
||||
if let Some(split) = snippet.find('(') {
|
||||
let trait_name = &snippet[0..split];
|
||||
let args = &snippet[split + 1..snippet.len() - 1];
|
||||
err.span_suggestion(
|
||||
data.span,
|
||||
"use angle brackets instead",
|
||||
format!("{}<{}>", trait_name, args),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
err.emit();
|
||||
(
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
param_mode,
|
||||
itctx,
|
||||
)
|
||||
.0,
|
||||
false,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
|
||||
};
|
||||
|
||||
let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
|
||||
GenericArg::Lifetime(_) => true,
|
||||
_ => false,
|
||||
});
|
||||
let first_generic_span = generic_args
|
||||
.args
|
||||
.iter()
|
||||
.map(|a| a.span())
|
||||
.chain(generic_args.bindings.iter().map(|b| b.span))
|
||||
.next();
|
||||
if !generic_args.parenthesized && !has_lifetimes {
|
||||
generic_args.args = self
|
||||
.elided_path_lifetimes(path_span, expected_lifetimes)
|
||||
.map(|lt| GenericArg::Lifetime(lt))
|
||||
.chain(generic_args.args.into_iter())
|
||||
.collect();
|
||||
if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
|
||||
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
|
||||
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
|
||||
let no_bindings = generic_args.bindings.is_empty();
|
||||
let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
|
||||
// If there are no (non-implicit) generic args or associated type
|
||||
// bindings, our suggestion includes the angle brackets.
|
||||
(true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
|
||||
} else {
|
||||
// Otherwise (sorry, this is kind of gross) we need to infer the
|
||||
// place to splice in the `'_, ` from the generics that do exist.
|
||||
let first_generic_span = first_generic_span
|
||||
.expect("already checked that non-lifetime args or bindings exist");
|
||||
(false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
|
||||
};
|
||||
match self.anonymous_lifetime_mode {
|
||||
// In create-parameter mode we error here because we don't want to support
|
||||
// deprecated impl elision in new features like impl elision and `async fn`,
|
||||
// both of which work using the `CreateParameter` mode:
|
||||
//
|
||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
path_span,
|
||||
E0726,
|
||||
"implicit elided lifetime not allowed here"
|
||||
);
|
||||
crate::lint::builtin::add_elided_lifetime_in_path_suggestion(
|
||||
&self.sess,
|
||||
&mut err,
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_sp,
|
||||
suggestion,
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
|
||||
self.resolver.lint_buffer().buffer_lint_with_diagnostic(
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
CRATE_NODE_ID,
|
||||
path_span,
|
||||
"hidden lifetime parameters in types are deprecated",
|
||||
builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_sp,
|
||||
suggestion,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let res = self.expect_full_res(segment.id);
|
||||
let id = if let Some(owner) = explicit_owner {
|
||||
self.lower_node_id_with_owner(segment.id, owner)
|
||||
} else {
|
||||
self.lower_node_id(segment.id)
|
||||
};
|
||||
debug!(
|
||||
"lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
|
||||
segment.ident, segment.id, id,
|
||||
);
|
||||
|
||||
hir::PathSegment {
|
||||
ident: segment.ident,
|
||||
hir_id: Some(id),
|
||||
res: Some(self.lower_res(res)),
|
||||
infer_args,
|
||||
args: if generic_args.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_angle_bracketed_parameter_data(
|
||||
&mut self,
|
||||
data: &AngleBracketedArgs,
|
||||
param_mode: ParamMode,
|
||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
|
||||
let has_non_lt_args = args.iter().any(|arg| match arg {
|
||||
ast::GenericArg::Lifetime(_) => false,
|
||||
ast::GenericArg::Type(_) => true,
|
||||
ast::GenericArg::Const(_) => true,
|
||||
});
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
|
||||
bindings: self.arena.alloc_from_iter(
|
||||
constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
|
||||
),
|
||||
parenthesized: false,
|
||||
},
|
||||
!has_non_lt_args && param_mode == ParamMode::Optional,
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_parenthesized_parameter_data(
|
||||
&mut self,
|
||||
data: &ParenthesizedArgs,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
// Switch to `PassThrough` mode for anonymous lifetimes; this
|
||||
// means that we permit things like `&Ref<T>`, where `Ref` has
|
||||
// a hidden lifetime parameter. This is needed for backwards
|
||||
// compatibility, even in contexts like an impl header where
|
||||
// we generally don't permit such things (see #51008).
|
||||
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
|
||||
let &ParenthesizedArgs { ref inputs, ref output, span } = data;
|
||||
let inputs = this.arena.alloc_from_iter(
|
||||
inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
|
||||
);
|
||||
let output_ty = match output {
|
||||
FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
|
||||
FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))];
|
||||
let binding = hir::TypeBinding {
|
||||
hir_id: this.next_id(),
|
||||
ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
|
||||
span: output_ty.span,
|
||||
kind: hir::TypeBindingKind::Equality { ty: output_ty },
|
||||
};
|
||||
(
|
||||
GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
|
||||
false,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_local(&mut self, l: &Local) -> (hir::Local<'hir>, SmallVec<[NodeId; 1]>) {
|
||||
let mut ids = SmallVec::<[NodeId; 1]>::new();
|
||||
if self.sess.features_untracked().impl_trait_in_bindings {
|
||||
|
@ -2387,12 +1970,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// "<Output = T>"
|
||||
let future_params = self.arena.alloc(hir::GenericArgs {
|
||||
args: &[],
|
||||
bindings: arena_vec![self; hir::TypeBinding {
|
||||
ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
|
||||
kind: hir::TypeBindingKind::Equality { ty: output_ty },
|
||||
hir_id: self.next_id(),
|
||||
span,
|
||||
}],
|
||||
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
|
||||
parenthesized: false,
|
||||
});
|
||||
|
||||
|
@ -2579,6 +2157,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
p: &PolyTraitRef,
|
||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
if p.trait_ref.constness.is_some() {
|
||||
self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented");
|
||||
}
|
||||
|
||||
let bound_generic_params = self.lower_generic_params(
|
||||
&p.bound_generic_params,
|
||||
&NodeMap::default(),
|
||||
|
@ -2648,250 +2230,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.expr_block(block, AttrVec::new())
|
||||
}
|
||||
|
||||
fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
let node = match p.kind {
|
||||
PatKind::Wild => hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, ident, ref sub) => {
|
||||
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
|
||||
let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub);
|
||||
node
|
||||
}
|
||||
PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
|
||||
PatKind::TupleStruct(ref path, ref pats) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
);
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
hir::PatKind::TupleStruct(qpath, pats, ddpos)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))))
|
||||
}
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
);
|
||||
hir::PatKind::Path(qpath)
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, etc) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
);
|
||||
|
||||
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat {
|
||||
hir_id: self.next_id(),
|
||||
ident: f.ident,
|
||||
pat: self.lower_pat(&f.pat),
|
||||
is_shorthand: f.is_shorthand,
|
||||
span: f.span,
|
||||
}));
|
||||
hir::PatKind::Struct(qpath, fs, etc)
|
||||
}
|
||||
PatKind::Tuple(ref pats) => {
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
|
||||
hir::PatKind::Tuple(pats, ddpos)
|
||||
}
|
||||
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
||||
PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl),
|
||||
PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range(
|
||||
self.lower_expr(e1),
|
||||
self.lower_expr(e2),
|
||||
self.lower_range_end(end),
|
||||
),
|
||||
PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
|
||||
PatKind::Rest => {
|
||||
// If we reach here the `..` pattern is not semantically allowed.
|
||||
self.ban_illegal_rest_pat(p.span)
|
||||
}
|
||||
PatKind::Paren(ref inner) => return self.lower_pat(inner),
|
||||
PatKind::Mac(_) => panic!("Shouldn't exist here"),
|
||||
};
|
||||
|
||||
self.pat_with_node_id_of(p, node)
|
||||
}
|
||||
|
||||
fn lower_pat_tuple(
|
||||
&mut self,
|
||||
pats: &[AstP<Pat>],
|
||||
ctx: &str,
|
||||
) -> (&'hir [&'hir hir::Pat<'hir>], Option<usize>) {
|
||||
let mut elems = Vec::with_capacity(pats.len());
|
||||
let mut rest = None;
|
||||
|
||||
let mut iter = pats.iter().enumerate();
|
||||
for (idx, pat) in iter.by_ref() {
|
||||
// Interpret the first `..` pattern as a sub-tuple pattern.
|
||||
// Note that unlike for slice patterns,
|
||||
// where `xs @ ..` is a legal sub-slice pattern,
|
||||
// it is not a legal sub-tuple pattern.
|
||||
if pat.is_rest() {
|
||||
rest = Some((idx, pat.span));
|
||||
break;
|
||||
}
|
||||
// It was not a sub-tuple pattern so lower it normally.
|
||||
elems.push(self.lower_pat(pat));
|
||||
}
|
||||
|
||||
for (_, pat) in iter {
|
||||
// There was a previous sub-tuple pattern; make sure we don't allow more...
|
||||
if pat.is_rest() {
|
||||
// ...but there was one again, so error.
|
||||
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
|
||||
} else {
|
||||
elems.push(self.lower_pat(pat));
|
||||
}
|
||||
}
|
||||
|
||||
(self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
|
||||
}
|
||||
|
||||
/// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
|
||||
/// `hir::PatKind::Slice(before, slice, after)`.
|
||||
///
|
||||
/// When encountering `($binding_mode $ident @)? ..` (`slice`),
|
||||
/// this is interpreted as a sub-slice pattern semantically.
|
||||
/// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
|
||||
fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind<'hir> {
|
||||
let mut before = Vec::new();
|
||||
let mut after = Vec::new();
|
||||
let mut slice = None;
|
||||
let mut prev_rest_span = None;
|
||||
|
||||
let mut iter = pats.iter();
|
||||
// Lower all the patterns until the first occurence of a sub-slice pattern.
|
||||
for pat in iter.by_ref() {
|
||||
match pat.kind {
|
||||
// Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
|
||||
PatKind::Rest => {
|
||||
prev_rest_span = Some(pat.span);
|
||||
slice = Some(self.pat_wild_with_node_id_of(pat));
|
||||
break;
|
||||
}
|
||||
// Found a sub-slice pattern `$binding_mode $ident @ ..`.
|
||||
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
|
||||
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
prev_rest_span = Some(sub.span);
|
||||
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
|
||||
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
|
||||
slice = Some(self.pat_with_node_id_of(pat, node));
|
||||
break;
|
||||
}
|
||||
// It was not a subslice pattern so lower it normally.
|
||||
_ => before.push(self.lower_pat(pat)),
|
||||
}
|
||||
}
|
||||
|
||||
// Lower all the patterns after the first sub-slice pattern.
|
||||
for pat in iter {
|
||||
// There was a previous subslice pattern; make sure we don't allow more.
|
||||
let rest_span = match pat.kind {
|
||||
PatKind::Rest => Some(pat.span),
|
||||
PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
|
||||
// The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
|
||||
after.push(self.pat_wild_with_node_id_of(pat));
|
||||
Some(sub.span)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(rest_span) = rest_span {
|
||||
// We have e.g., `[a, .., b, ..]`. That's no good, error!
|
||||
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
|
||||
} else {
|
||||
// Lower the pattern normally.
|
||||
after.push(self.lower_pat(pat));
|
||||
}
|
||||
}
|
||||
|
||||
hir::PatKind::Slice(
|
||||
self.arena.alloc_from_iter(before),
|
||||
slice,
|
||||
self.arena.alloc_from_iter(after),
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_pat_ident(
|
||||
&mut self,
|
||||
p: &Pat,
|
||||
binding_mode: &BindingMode,
|
||||
ident: Ident,
|
||||
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
|
||||
) -> hir::PatKind<'hir> {
|
||||
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
|
||||
// `None` can occur in body-less function signatures
|
||||
res @ None | res @ Some(Res::Local(_)) => {
|
||||
let canonical_id = match res {
|
||||
Some(Res::Local(id)) => id,
|
||||
_ => p.id,
|
||||
};
|
||||
|
||||
hir::PatKind::Binding(
|
||||
self.lower_binding_mode(binding_mode),
|
||||
self.lower_node_id(canonical_id),
|
||||
ident,
|
||||
lower_sub(self),
|
||||
)
|
||||
}
|
||||
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
span: ident.span,
|
||||
res: self.lower_res(res),
|
||||
segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
|
||||
}),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
self.pat_with_node_id_of(p, hir::PatKind::Wild)
|
||||
}
|
||||
|
||||
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
|
||||
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
|
||||
}
|
||||
|
||||
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
||||
fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
|
||||
self.diagnostic()
|
||||
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
|
||||
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
|
||||
.span_label(prev_sp, "previously used here")
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// Used to ban the `..` pattern in places it shouldn't be semantically.
|
||||
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
|
||||
self.diagnostic()
|
||||
.struct_span_err(sp, "`..` patterns are not allowed here")
|
||||
.note("only allowed in tuple, tuple struct, and slice patterns")
|
||||
.emit();
|
||||
|
||||
// We're not in a list context so `..` can be reasonably treated
|
||||
// as `_` because it should always be valid and roughly matches the
|
||||
// intent of `..` (notice that the rest of a single slot is that slot).
|
||||
hir::PatKind::Wild
|
||||
}
|
||||
|
||||
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
|
||||
match *e {
|
||||
RangeEnd::Included(_) => hir::RangeEnd::Included,
|
||||
RangeEnd::Excluded => hir::RangeEnd::Excluded,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
|
||||
self.with_new_scopes(|this| hir::AnonConst {
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
|
@ -2951,15 +2289,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
|
||||
match *b {
|
||||
BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
|
||||
BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
|
||||
BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
|
||||
BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
|
||||
match u {
|
||||
CompilerGenerated => hir::UnsafeSource::CompilerGenerated,
|
||||
|
|
262
src/librustc_ast_lowering/pat.rs
Normal file
262
src/librustc_ast_lowering/pat.rs
Normal file
|
@ -0,0 +1,262 @@
|
|||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_span::{source_map::Spanned, Span};
|
||||
use syntax::ast::*;
|
||||
use syntax::ptr::P;
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
let node = match p.kind {
|
||||
PatKind::Wild => hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, ident, ref sub) => {
|
||||
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
|
||||
let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub);
|
||||
node
|
||||
}
|
||||
PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
|
||||
PatKind::TupleStruct(ref path, ref pats) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
);
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
hir::PatKind::TupleStruct(qpath, pats, ddpos)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))))
|
||||
}
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
);
|
||||
hir::PatKind::Path(qpath)
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, etc) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
);
|
||||
|
||||
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat {
|
||||
hir_id: self.next_id(),
|
||||
ident: f.ident,
|
||||
pat: self.lower_pat(&f.pat),
|
||||
is_shorthand: f.is_shorthand,
|
||||
span: f.span,
|
||||
}));
|
||||
hir::PatKind::Struct(qpath, fs, etc)
|
||||
}
|
||||
PatKind::Tuple(ref pats) => {
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
|
||||
hir::PatKind::Tuple(pats, ddpos)
|
||||
}
|
||||
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
||||
PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl),
|
||||
PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range(
|
||||
self.lower_expr(e1),
|
||||
self.lower_expr(e2),
|
||||
self.lower_range_end(end),
|
||||
),
|
||||
PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
|
||||
PatKind::Rest => {
|
||||
// If we reach here the `..` pattern is not semantically allowed.
|
||||
self.ban_illegal_rest_pat(p.span)
|
||||
}
|
||||
PatKind::Paren(ref inner) => return self.lower_pat(inner),
|
||||
PatKind::Mac(_) => panic!("Shouldn't exist here"),
|
||||
};
|
||||
|
||||
self.pat_with_node_id_of(p, node)
|
||||
}
|
||||
|
||||
fn lower_pat_tuple(
|
||||
&mut self,
|
||||
pats: &[P<Pat>],
|
||||
ctx: &str,
|
||||
) -> (&'hir [&'hir hir::Pat<'hir>], Option<usize>) {
|
||||
let mut elems = Vec::with_capacity(pats.len());
|
||||
let mut rest = None;
|
||||
|
||||
let mut iter = pats.iter().enumerate();
|
||||
for (idx, pat) in iter.by_ref() {
|
||||
// Interpret the first `..` pattern as a sub-tuple pattern.
|
||||
// Note that unlike for slice patterns,
|
||||
// where `xs @ ..` is a legal sub-slice pattern,
|
||||
// it is not a legal sub-tuple pattern.
|
||||
if pat.is_rest() {
|
||||
rest = Some((idx, pat.span));
|
||||
break;
|
||||
}
|
||||
// It was not a sub-tuple pattern so lower it normally.
|
||||
elems.push(self.lower_pat(pat));
|
||||
}
|
||||
|
||||
for (_, pat) in iter {
|
||||
// There was a previous sub-tuple pattern; make sure we don't allow more...
|
||||
if pat.is_rest() {
|
||||
// ...but there was one again, so error.
|
||||
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
|
||||
} else {
|
||||
elems.push(self.lower_pat(pat));
|
||||
}
|
||||
}
|
||||
|
||||
(self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
|
||||
}
|
||||
|
||||
/// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
|
||||
/// `hir::PatKind::Slice(before, slice, after)`.
|
||||
///
|
||||
/// When encountering `($binding_mode $ident @)? ..` (`slice`),
|
||||
/// this is interpreted as a sub-slice pattern semantically.
|
||||
/// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
|
||||
fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
|
||||
let mut before = Vec::new();
|
||||
let mut after = Vec::new();
|
||||
let mut slice = None;
|
||||
let mut prev_rest_span = None;
|
||||
|
||||
let mut iter = pats.iter();
|
||||
// Lower all the patterns until the first occurence of a sub-slice pattern.
|
||||
for pat in iter.by_ref() {
|
||||
match pat.kind {
|
||||
// Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
|
||||
PatKind::Rest => {
|
||||
prev_rest_span = Some(pat.span);
|
||||
slice = Some(self.pat_wild_with_node_id_of(pat));
|
||||
break;
|
||||
}
|
||||
// Found a sub-slice pattern `$binding_mode $ident @ ..`.
|
||||
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
|
||||
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
prev_rest_span = Some(sub.span);
|
||||
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
|
||||
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
|
||||
slice = Some(self.pat_with_node_id_of(pat, node));
|
||||
break;
|
||||
}
|
||||
// It was not a subslice pattern so lower it normally.
|
||||
_ => before.push(self.lower_pat(pat)),
|
||||
}
|
||||
}
|
||||
|
||||
// Lower all the patterns after the first sub-slice pattern.
|
||||
for pat in iter {
|
||||
// There was a previous subslice pattern; make sure we don't allow more.
|
||||
let rest_span = match pat.kind {
|
||||
PatKind::Rest => Some(pat.span),
|
||||
PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
|
||||
// The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
|
||||
after.push(self.pat_wild_with_node_id_of(pat));
|
||||
Some(sub.span)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(rest_span) = rest_span {
|
||||
// We have e.g., `[a, .., b, ..]`. That's no good, error!
|
||||
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
|
||||
} else {
|
||||
// Lower the pattern normally.
|
||||
after.push(self.lower_pat(pat));
|
||||
}
|
||||
}
|
||||
|
||||
hir::PatKind::Slice(
|
||||
self.arena.alloc_from_iter(before),
|
||||
slice,
|
||||
self.arena.alloc_from_iter(after),
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_pat_ident(
|
||||
&mut self,
|
||||
p: &Pat,
|
||||
binding_mode: &BindingMode,
|
||||
ident: Ident,
|
||||
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
|
||||
) -> hir::PatKind<'hir> {
|
||||
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
|
||||
// `None` can occur in body-less function signatures
|
||||
res @ None | res @ Some(Res::Local(_)) => {
|
||||
let canonical_id = match res {
|
||||
Some(Res::Local(id)) => id,
|
||||
_ => p.id,
|
||||
};
|
||||
|
||||
hir::PatKind::Binding(
|
||||
self.lower_binding_mode(binding_mode),
|
||||
self.lower_node_id(canonical_id),
|
||||
ident,
|
||||
lower_sub(self),
|
||||
)
|
||||
}
|
||||
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
span: ident.span,
|
||||
res: self.lower_res(res),
|
||||
segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
|
||||
}),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
|
||||
match *b {
|
||||
BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
|
||||
BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
|
||||
BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
|
||||
BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
|
||||
}
|
||||
}
|
||||
|
||||
fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
self.pat_with_node_id_of(p, hir::PatKind::Wild)
|
||||
}
|
||||
|
||||
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
|
||||
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
|
||||
}
|
||||
|
||||
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
||||
fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
|
||||
self.diagnostic()
|
||||
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
|
||||
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
|
||||
.span_label(prev_sp, "previously used here")
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// Used to ban the `..` pattern in places it shouldn't be semantically.
|
||||
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
|
||||
self.diagnostic()
|
||||
.struct_span_err(sp, "`..` patterns are not allowed here")
|
||||
.note("only allowed in tuple, tuple struct, and slice patterns")
|
||||
.emit();
|
||||
|
||||
// We're not in a list context so `..` can be reasonably treated
|
||||
// as `_` because it should always be valid and roughly matches the
|
||||
// intent of `..` (notice that the rest of a single slot is that slot).
|
||||
hir::PatKind::Wild
|
||||
}
|
||||
|
||||
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
|
||||
match *e {
|
||||
RangeEnd::Included(_) => hir::RangeEnd::Included,
|
||||
RangeEnd::Excluded => hir::RangeEnd::Excluded,
|
||||
}
|
||||
}
|
||||
}
|
422
src/librustc_ast_lowering/path.rs
Normal file
422
src/librustc_ast_lowering/path.rs
Normal file
|
@ -0,0 +1,422 @@
|
|||
use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode};
|
||||
use super::{GenericArgsCtor, ParenthesizedGenericArgs};
|
||||
|
||||
use rustc::lint::builtin::{self, ELIDED_LIFETIMES_IN_PATHS};
|
||||
use rustc::span_bug;
|
||||
use rustc_error_codes::*;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, PartialRes, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_span::Span;
|
||||
use syntax::ast::{self, *};
|
||||
|
||||
use log::debug;
|
||||
use smallvec::smallvec;
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
crate fn lower_qpath(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
qself: &Option<QSelf>,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
|
||||
|
||||
let partial_res =
|
||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
|
||||
let proj_start = p.segments.len() - partial_res.unresolved_segments();
|
||||
let path = self.arena.alloc(hir::Path {
|
||||
res: self.lower_res(partial_res.base_res()),
|
||||
segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
|
||||
|(i, segment)| {
|
||||
let param_mode = match (qself_position, param_mode) {
|
||||
(Some(j), ParamMode::Optional) if i < j => {
|
||||
// This segment is part of the trait path in a
|
||||
// qualified path - one of `a`, `b` or `Trait`
|
||||
// in `<X as a::b::Trait>::T::U::method`.
|
||||
ParamMode::Explicit
|
||||
}
|
||||
_ => param_mode,
|
||||
};
|
||||
|
||||
// Figure out if this is a type/trait segment,
|
||||
// which may need lifetime elision performed.
|
||||
let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
|
||||
krate: def_id.krate,
|
||||
index: this.resolver.def_key(def_id).parent.expect("missing parent"),
|
||||
};
|
||||
let type_def_id = match partial_res.base_res() {
|
||||
Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
|
||||
Some(parent_def_id(self, def_id))
|
||||
}
|
||||
Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
|
||||
Some(parent_def_id(self, def_id))
|
||||
}
|
||||
Res::Def(DefKind::Struct, def_id)
|
||||
| Res::Def(DefKind::Union, def_id)
|
||||
| Res::Def(DefKind::Enum, def_id)
|
||||
| Res::Def(DefKind::TyAlias, def_id)
|
||||
| Res::Def(DefKind::Trait, def_id)
|
||||
if i + 1 == proj_start =>
|
||||
{
|
||||
Some(def_id)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let parenthesized_generic_args = match partial_res.base_res() {
|
||||
// `a::b::Trait(Args)`
|
||||
Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
|
||||
ParenthesizedGenericArgs::Ok
|
||||
}
|
||||
// `a::b::Trait(Args)::TraitItem`
|
||||
Res::Def(DefKind::Method, _)
|
||||
| Res::Def(DefKind::AssocConst, _)
|
||||
| Res::Def(DefKind::AssocTy, _)
|
||||
if i + 2 == proj_start =>
|
||||
{
|
||||
ParenthesizedGenericArgs::Ok
|
||||
}
|
||||
// Avoid duplicated errors.
|
||||
Res::Err => ParenthesizedGenericArgs::Ok,
|
||||
// An error
|
||||
_ => ParenthesizedGenericArgs::Err,
|
||||
};
|
||||
|
||||
let num_lifetimes = type_def_id.map_or(0, |def_id| {
|
||||
if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
|
||||
return n;
|
||||
}
|
||||
assert!(!def_id.is_local());
|
||||
let n = self.resolver.item_generics_num_lifetimes(def_id, self.sess);
|
||||
self.type_def_lifetime_params.insert(def_id, n);
|
||||
n
|
||||
});
|
||||
self.lower_path_segment(
|
||||
p.span,
|
||||
segment,
|
||||
param_mode,
|
||||
num_lifetimes,
|
||||
parenthesized_generic_args,
|
||||
itctx.reborrow(),
|
||||
None,
|
||||
)
|
||||
},
|
||||
)),
|
||||
span: p.span,
|
||||
});
|
||||
|
||||
// Simple case, either no projections, or only fully-qualified.
|
||||
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
|
||||
if partial_res.unresolved_segments() == 0 {
|
||||
return hir::QPath::Resolved(qself, path);
|
||||
}
|
||||
|
||||
// Create the innermost type that we're projecting from.
|
||||
let mut ty = if path.segments.is_empty() {
|
||||
// If the base path is empty that means there exists a
|
||||
// syntactical `Self`, e.g., `&i32` in `<&i32>::clone`.
|
||||
qself.expect("missing QSelf for <T>::...")
|
||||
} else {
|
||||
// Otherwise, the base path is an implicit `Self` type path,
|
||||
// e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in
|
||||
// `<I as Iterator>::Item::default`.
|
||||
let new_id = self.next_id();
|
||||
self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)))
|
||||
};
|
||||
|
||||
// Anything after the base path are associated "extensions",
|
||||
// out of which all but the last one are associated types,
|
||||
// e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`:
|
||||
// * base path is `std::vec::Vec<T>`
|
||||
// * "extensions" are `IntoIter`, `Item` and `clone`
|
||||
// * type nodes are:
|
||||
// 1. `std::vec::Vec<T>` (created above)
|
||||
// 2. `<std::vec::Vec<T>>::IntoIter`
|
||||
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
|
||||
// * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
|
||||
for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
|
||||
let segment = self.arena.alloc(self.lower_path_segment(
|
||||
p.span,
|
||||
segment,
|
||||
param_mode,
|
||||
0,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
itctx.reborrow(),
|
||||
None,
|
||||
));
|
||||
let qpath = hir::QPath::TypeRelative(ty, segment);
|
||||
|
||||
// It's finished, return the extension of the right node type.
|
||||
if i == p.segments.len() - 1 {
|
||||
return qpath;
|
||||
}
|
||||
|
||||
// Wrap the associated extension in another type node.
|
||||
let new_id = self.next_id();
|
||||
ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath));
|
||||
}
|
||||
|
||||
// We should've returned in the for loop above.
|
||||
span_bug!(
|
||||
p.span,
|
||||
"lower_qpath: no final extension segment in {}..{}",
|
||||
proj_start,
|
||||
p.segments.len()
|
||||
)
|
||||
}
|
||||
|
||||
crate fn lower_path_extra(
|
||||
&mut self,
|
||||
res: Res,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
explicit_owner: Option<NodeId>,
|
||||
) -> &'hir hir::Path<'hir> {
|
||||
self.arena.alloc(hir::Path {
|
||||
res,
|
||||
segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
|
||||
self.lower_path_segment(
|
||||
p.span,
|
||||
segment,
|
||||
param_mode,
|
||||
0,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::disallowed(),
|
||||
explicit_owner,
|
||||
)
|
||||
})),
|
||||
span: p.span,
|
||||
})
|
||||
}
|
||||
|
||||
crate fn lower_path(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
) -> &'hir hir::Path<'hir> {
|
||||
let res = self.expect_full_res(id);
|
||||
let res = self.lower_res(res);
|
||||
self.lower_path_extra(res, p, param_mode, None)
|
||||
}
|
||||
|
||||
crate fn lower_path_segment(
|
||||
&mut self,
|
||||
path_span: Span,
|
||||
segment: &PathSegment,
|
||||
param_mode: ParamMode,
|
||||
expected_lifetimes: usize,
|
||||
parenthesized_generic_args: ParenthesizedGenericArgs,
|
||||
itctx: ImplTraitContext<'_, 'hir>,
|
||||
explicit_owner: Option<NodeId>,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
|
||||
let msg = "parenthesized type parameters may only be used with a `Fn` trait";
|
||||
match **generic_args {
|
||||
GenericArgs::AngleBracketed(ref data) => {
|
||||
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
|
||||
}
|
||||
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
|
||||
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
|
||||
ParenthesizedGenericArgs::Err => {
|
||||
let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
|
||||
err.span_label(data.span, "only `Fn` traits may use parentheses");
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
|
||||
// Do not suggest going from `Trait()` to `Trait<>`
|
||||
if data.inputs.len() > 0 {
|
||||
if let Some(split) = snippet.find('(') {
|
||||
let trait_name = &snippet[0..split];
|
||||
let args = &snippet[split + 1..snippet.len() - 1];
|
||||
err.span_suggestion(
|
||||
data.span,
|
||||
"use angle brackets instead",
|
||||
format!("{}<{}>", trait_name, args),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
err.emit();
|
||||
(
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
param_mode,
|
||||
itctx,
|
||||
)
|
||||
.0,
|
||||
false,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
|
||||
};
|
||||
|
||||
let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
|
||||
GenericArg::Lifetime(_) => true,
|
||||
_ => false,
|
||||
});
|
||||
let first_generic_span = generic_args
|
||||
.args
|
||||
.iter()
|
||||
.map(|a| a.span())
|
||||
.chain(generic_args.bindings.iter().map(|b| b.span))
|
||||
.next();
|
||||
if !generic_args.parenthesized && !has_lifetimes {
|
||||
generic_args.args = self
|
||||
.elided_path_lifetimes(path_span, expected_lifetimes)
|
||||
.map(|lt| GenericArg::Lifetime(lt))
|
||||
.chain(generic_args.args.into_iter())
|
||||
.collect();
|
||||
if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
|
||||
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
|
||||
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
|
||||
let no_bindings = generic_args.bindings.is_empty();
|
||||
let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
|
||||
// If there are no (non-implicit) generic args or associated type
|
||||
// bindings, our suggestion includes the angle brackets.
|
||||
(true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
|
||||
} else {
|
||||
// Otherwise (sorry, this is kind of gross) we need to infer the
|
||||
// place to splice in the `'_, ` from the generics that do exist.
|
||||
let first_generic_span = first_generic_span
|
||||
.expect("already checked that non-lifetime args or bindings exist");
|
||||
(false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
|
||||
};
|
||||
match self.anonymous_lifetime_mode {
|
||||
// In create-parameter mode we error here because we don't want to support
|
||||
// deprecated impl elision in new features like impl elision and `async fn`,
|
||||
// both of which work using the `CreateParameter` mode:
|
||||
//
|
||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
path_span,
|
||||
E0726,
|
||||
"implicit elided lifetime not allowed here"
|
||||
);
|
||||
crate::lint::builtin::add_elided_lifetime_in_path_suggestion(
|
||||
&self.sess,
|
||||
&mut err,
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_sp,
|
||||
suggestion,
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
|
||||
self.resolver.lint_buffer().buffer_lint_with_diagnostic(
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
CRATE_NODE_ID,
|
||||
path_span,
|
||||
"hidden lifetime parameters in types are deprecated",
|
||||
builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_sp,
|
||||
suggestion,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let res = self.expect_full_res(segment.id);
|
||||
let id = if let Some(owner) = explicit_owner {
|
||||
self.lower_node_id_with_owner(segment.id, owner)
|
||||
} else {
|
||||
self.lower_node_id(segment.id)
|
||||
};
|
||||
debug!(
|
||||
"lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
|
||||
segment.ident, segment.id, id,
|
||||
);
|
||||
|
||||
hir::PathSegment {
|
||||
ident: segment.ident,
|
||||
hir_id: Some(id),
|
||||
res: Some(self.lower_res(res)),
|
||||
infer_args,
|
||||
args: if generic_args.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_angle_bracketed_parameter_data(
|
||||
&mut self,
|
||||
data: &AngleBracketedArgs,
|
||||
param_mode: ParamMode,
|
||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
|
||||
let has_non_lt_args = args.iter().any(|arg| match arg {
|
||||
ast::GenericArg::Lifetime(_) => false,
|
||||
ast::GenericArg::Type(_) => true,
|
||||
ast::GenericArg::Const(_) => true,
|
||||
});
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
|
||||
bindings: self.arena.alloc_from_iter(
|
||||
constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
|
||||
),
|
||||
parenthesized: false,
|
||||
},
|
||||
!has_non_lt_args && param_mode == ParamMode::Optional,
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_parenthesized_parameter_data(
|
||||
&mut self,
|
||||
data: &ParenthesizedArgs,
|
||||
) -> (GenericArgsCtor<'hir>, bool) {
|
||||
// Switch to `PassThrough` mode for anonymous lifetimes; this
|
||||
// means that we permit things like `&Ref<T>`, where `Ref` has
|
||||
// a hidden lifetime parameter. This is needed for backwards
|
||||
// compatibility, even in contexts like an impl header where
|
||||
// we generally don't permit such things (see #51008).
|
||||
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
|
||||
let &ParenthesizedArgs { ref inputs, ref output, span } = data;
|
||||
let inputs = this.arena.alloc_from_iter(
|
||||
inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
|
||||
);
|
||||
let output_ty = match output {
|
||||
FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
|
||||
FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))];
|
||||
let binding = this.output_ty_binding(output_ty.span, output_ty);
|
||||
(
|
||||
GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
|
||||
false,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// An associated type binding `Output = $ty`.
|
||||
crate fn output_ty_binding(
|
||||
&mut self,
|
||||
span: Span,
|
||||
ty: &'hir hir::Ty<'hir>,
|
||||
) -> hir::TypeBinding<'hir> {
|
||||
let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
|
||||
let kind = hir::TypeBindingKind::Equality { ty };
|
||||
hir::TypeBinding { hir_id: self.next_id(), span, ident, kind }
|
||||
}
|
||||
}
|
|
@ -67,6 +67,7 @@ macro_rules! unlikely {
|
|||
pub mod base_n;
|
||||
pub mod binary_search_util;
|
||||
pub mod box_region;
|
||||
pub mod captures;
|
||||
pub mod const_cstr;
|
||||
pub mod flock;
|
||||
pub mod fx;
|
||||
|
|
|
@ -110,7 +110,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
}
|
||||
|
||||
pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
|
||||
ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID }
|
||||
ast::TraitRef { path, constness: None, ref_id: ast::DUMMY_NODE_ID }
|
||||
}
|
||||
|
||||
pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
|
||||
|
|
|
@ -544,6 +544,12 @@ declare_features! (
|
|||
/// For example, you can write `x @ Some(y)`.
|
||||
(active, bindings_after_at, "1.41.0", Some(65490), None),
|
||||
|
||||
/// Allows `impl const Trait for T` syntax.
|
||||
(active, const_trait_impl, "1.42.0", Some(67792), None),
|
||||
|
||||
/// Allows `T: ?const Trait` syntax in bounds.
|
||||
(active, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -559,4 +565,6 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
|
|||
sym::or_patterns,
|
||||
sym::let_chains,
|
||||
sym::raw_dylib,
|
||||
sym::const_trait_impl,
|
||||
sym::const_trait_bound_opt_out,
|
||||
];
|
||||
|
|
|
@ -1875,6 +1875,9 @@ pub enum ImplItemKind<'hir> {
|
|||
OpaqueTy(GenericBounds<'hir>),
|
||||
}
|
||||
|
||||
// The name of the associated type for `Fn` return types.
|
||||
pub const FN_OUTPUT_NAME: Symbol = sym::Output;
|
||||
|
||||
/// Bind a type to an associated type (i.e., `A = Foo`).
|
||||
///
|
||||
/// Bindings like `A: Debug` are represented as a special type `A =
|
||||
|
|
|
@ -12,8 +12,7 @@ use rustc::session::{CrateDisambiguator, Session};
|
|||
use rustc::ty::TyCtxt;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_target::spec::{PanicStrategy, TargetTriple};
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ use rustc::mir::{self, interpret, BodyAndCache, Promoted};
|
|||
use rustc::session::Session;
|
||||
use rustc::ty::codec::TyDecoder;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::util::captures::Captures;
|
||||
use rustc::util::common::record_time;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
|
|
|
@ -478,6 +478,10 @@ impl CStore {
|
|||
pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
|
||||
self.get_crate_data(cnum).source.clone()
|
||||
}
|
||||
|
||||
pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
|
||||
self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateStore for CStore {
|
||||
|
@ -485,10 +489,6 @@ impl CrateStore for CStore {
|
|||
self
|
||||
}
|
||||
|
||||
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics {
|
||||
self.get_crate_data(def.krate).get_generics(def.index, sess)
|
||||
}
|
||||
|
||||
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol {
|
||||
self.get_crate_data(cnum).root.name
|
||||
}
|
||||
|
|
|
@ -115,28 +115,31 @@ pub(super) fn op_to_const<'tcx>(
|
|||
// by-val is if we are in const_field, i.e., if this is (a field of) something that we
|
||||
// "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
|
||||
// structs containing such.
|
||||
op.try_as_mplace()
|
||||
op.try_as_mplace(ecx)
|
||||
};
|
||||
let val = match immediate {
|
||||
Ok(mplace) => {
|
||||
let ptr = mplace.ptr.assert_ptr();
|
||||
|
||||
let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr {
|
||||
Scalar::Ptr(ptr) => {
|
||||
let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
|
||||
ConstValue::ByRef { alloc, offset: ptr.offset }
|
||||
}
|
||||
Scalar::Raw { data, .. } => {
|
||||
assert!(mplace.layout.is_zst());
|
||||
assert_eq!(
|
||||
data,
|
||||
mplace.layout.align.abi.bytes().into(),
|
||||
"this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what
|
||||
value this integer address must have",
|
||||
);
|
||||
ConstValue::Scalar(Scalar::zst())
|
||||
}
|
||||
};
|
||||
let val = match immediate {
|
||||
Ok(mplace) => to_const_value(mplace),
|
||||
// see comment on `let try_as_immediate` above
|
||||
Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x {
|
||||
ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s),
|
||||
ScalarMaybeUndef::Undef => {
|
||||
// When coming out of "normal CTFE", we'll always have an `Indirect` operand as
|
||||
// argument and we will not need this. The only way we can already have an
|
||||
// `Immediate` is when we are called from `const_field`, and that `Immediate`
|
||||
// comes from a constant so it can happen have `Undef`, because the indirect
|
||||
// memory that was read had undefined bytes.
|
||||
let mplace = op.assert_mem_place();
|
||||
let ptr = mplace.ptr.assert_ptr();
|
||||
let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
|
||||
ConstValue::ByRef { alloc, offset: ptr.offset }
|
||||
}
|
||||
ScalarMaybeUndef::Undef => to_const_value(op.assert_mem_place(ecx)),
|
||||
},
|
||||
Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => {
|
||||
let (data, start) = match a.not_undef().unwrap() {
|
||||
|
|
|
@ -229,6 +229,7 @@ use self::SliceKind::*;
|
|||
use self::Usefulness::*;
|
||||
use self::WitnessPreference::*;
|
||||
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::vec::Idx;
|
||||
|
||||
|
@ -243,7 +244,6 @@ use rustc_hir::{HirId, RangeEnd};
|
|||
use rustc::lint;
|
||||
use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
|
||||
use rustc::mir::Field;
|
||||
use rustc::util::captures::Captures;
|
||||
use rustc::util::common::ErrorReported;
|
||||
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
|
|
@ -20,7 +20,7 @@ use rustc_macros::HashStable;
|
|||
use rustc_span::source_map::{self, Span, DUMMY_SP};
|
||||
|
||||
use super::{
|
||||
Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy,
|
||||
Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
|
||||
ScalarMaybeUndef, StackPopInfo,
|
||||
};
|
||||
|
||||
|
@ -393,7 +393,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// This can fail to provide an answer for extern types.
|
||||
pub(super) fn size_and_align_of(
|
||||
&self,
|
||||
metadata: Option<Scalar<M::PointerTag>>,
|
||||
metadata: MemPlaceMeta<M::PointerTag>,
|
||||
layout: TyLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, Option<(Size, Align)>> {
|
||||
if !layout.is_unsized() {
|
||||
|
@ -465,14 +465,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Ok(Some((size, align)))
|
||||
}
|
||||
ty::Dynamic(..) => {
|
||||
let vtable = metadata.expect("dyn trait fat ptr must have vtable");
|
||||
let vtable = metadata.unwrap_meta();
|
||||
// Read size and align from vtable (already checks size).
|
||||
Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
|
||||
}
|
||||
|
||||
ty::Slice(_) | ty::Str => {
|
||||
let len =
|
||||
metadata.expect("slice fat ptr must have length").to_machine_usize(self)?;
|
||||
let len = metadata.unwrap_meta().to_machine_usize(self)?;
|
||||
let elem = layout.field(self, 0)?;
|
||||
|
||||
// Make sure the slice is not too big.
|
||||
|
@ -818,8 +817,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
" by align({}){} ref:",
|
||||
mplace.align.bytes(),
|
||||
match mplace.meta {
|
||||
Some(meta) => format!(" meta({:?})", meta),
|
||||
None => String::new(),
|
||||
MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
|
||||
MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
|
||||
}
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
@ -193,7 +193,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
|
|||
{
|
||||
// Validation has already errored on an invalid vtable pointer so we can safely not
|
||||
// do anything if this is not a real pointer.
|
||||
if let Scalar::Ptr(vtable) = mplace.meta.unwrap() {
|
||||
if let Scalar::Ptr(vtable) = mplace.meta.unwrap_meta() {
|
||||
// Explicitly choose `Immutable` here, since vtables are immutable, even
|
||||
// if the reference of the fat pointer is mutable.
|
||||
self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?;
|
||||
|
@ -226,7 +226,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
|
|||
| (InternMode::Const, hir::Mutability::Mut) => match referenced_ty.kind {
|
||||
ty::Array(_, n)
|
||||
if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {}
|
||||
ty::Slice(_) if mplace.meta.unwrap().to_machine_usize(self.ecx)? == 0 => {}
|
||||
ty::Slice(_)
|
||||
if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? == 0 => {}
|
||||
_ => bug!("const qualif failed to prevent mutable references"),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one pla
|
|||
|
||||
pub use self::eval_context::{Frame, InterpCx, LocalState, LocalValue, StackPopCleanup};
|
||||
|
||||
pub use self::place::{MPlaceTy, MemPlace, Place, PlaceTy};
|
||||
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
|
||||
|
||||
pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind};
|
||||
|
||||
|
|
|
@ -153,30 +153,6 @@ pub enum Operand<Tag = (), Id = AllocId> {
|
|||
Indirect(MemPlace<Tag, Id>),
|
||||
}
|
||||
|
||||
impl<Tag> Operand<Tag> {
|
||||
#[inline]
|
||||
pub fn assert_mem_place(self) -> MemPlace<Tag>
|
||||
where
|
||||
Tag: ::std::fmt::Debug,
|
||||
{
|
||||
match self {
|
||||
Operand::Indirect(mplace) => mplace,
|
||||
_ => bug!("assert_mem_place: expected Operand::Indirect, got {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn assert_immediate(self) -> Immediate<Tag>
|
||||
where
|
||||
Tag: ::std::fmt::Debug,
|
||||
{
|
||||
match self {
|
||||
Operand::Immediate(imm) => imm,
|
||||
_ => bug!("assert_immediate: expected Operand::Immediate, got {:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct OpTy<'tcx, Tag = ()> {
|
||||
op: Operand<Tag>, // Keep this private; it helps enforce invariants.
|
||||
|
@ -267,7 +243,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
&self,
|
||||
op: OpTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
match op.try_as_mplace() {
|
||||
match op.try_as_mplace(self) {
|
||||
Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
|
||||
Err(imm) => Ok(imm.into()), // Nothing to cast/force
|
||||
}
|
||||
|
@ -335,7 +311,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
&self,
|
||||
src: OpTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
|
||||
Ok(match src.try_as_mplace() {
|
||||
Ok(match src.try_as_mplace(self) {
|
||||
Ok(mplace) => {
|
||||
if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
|
||||
Ok(val)
|
||||
|
@ -383,7 +359,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
op: OpTy<'tcx, M::PointerTag>,
|
||||
field: u64,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
let base = match op.try_as_mplace() {
|
||||
let base = match op.try_as_mplace(self) {
|
||||
Ok(mplace) => {
|
||||
// The easy case
|
||||
let field = self.mplace_field(mplace, field)?;
|
||||
|
@ -420,7 +396,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
variant: VariantIdx,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
// Downcasts only change the layout
|
||||
Ok(match op.try_as_mplace() {
|
||||
Ok(match op.try_as_mplace(self) {
|
||||
Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(),
|
||||
Err(..) => {
|
||||
let layout = op.layout.for_variant(self, variant);
|
||||
|
@ -439,30 +415,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Field(field, _) => self.operand_field(base, field.index() as u64)?,
|
||||
Downcast(_, variant) => self.operand_downcast(base, variant)?,
|
||||
Deref => self.deref_operand(base)?.into(),
|
||||
ConstantIndex { .. } | Index(_) if base.layout.is_zst() => {
|
||||
OpTy {
|
||||
op: Operand::Immediate(Scalar::zst().into()),
|
||||
// the actual index doesn't matter, so we just pick a convenient one like 0
|
||||
layout: base.layout.field(self, 0)?,
|
||||
}
|
||||
}
|
||||
Subslice { from, to, from_end } if base.layout.is_zst() => {
|
||||
let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind {
|
||||
elem_ty
|
||||
} else {
|
||||
bug!("slices shouldn't be zero-sized");
|
||||
};
|
||||
assert!(!from_end, "arrays shouldn't be subsliced from the end");
|
||||
|
||||
OpTy {
|
||||
op: Operand::Immediate(Scalar::zst().into()),
|
||||
layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?,
|
||||
}
|
||||
}
|
||||
Subslice { .. } | ConstantIndex { .. } | Index(_) => {
|
||||
// The rest should only occur as mplace, we do not use Immediates for types
|
||||
// allowing such operations. This matches place_projection forcing an allocation.
|
||||
let mplace = base.assert_mem_place();
|
||||
let mplace = base.assert_mem_place(self);
|
||||
self.mplace_projection(mplace, proj_elem)?.into()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -20,6 +20,47 @@ use super::{
|
|||
RawConst, Scalar, ScalarMaybeUndef,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
|
||||
/// Information required for the sound usage of a `MemPlace`.
|
||||
pub enum MemPlaceMeta<Tag = (), Id = AllocId> {
|
||||
/// The unsized payload (e.g. length for slices or vtable pointer for trait objects).
|
||||
Meta(Scalar<Tag, Id>),
|
||||
/// `Sized` types or unsized `extern type`
|
||||
None,
|
||||
/// The address of this place may not be taken. This protects the `MemPlace` from coming from
|
||||
/// a ZST Operand with a backing allocation and being converted to an integer address. This
|
||||
/// should be impossible, because you can't take the address of an operand, but this is a second
|
||||
/// protection layer ensuring that we don't mess up.
|
||||
Poison,
|
||||
}
|
||||
|
||||
impl<Tag, Id> MemPlaceMeta<Tag, Id> {
|
||||
pub fn unwrap_meta(self) -> Scalar<Tag, Id> {
|
||||
match self {
|
||||
Self::Meta(s) => s,
|
||||
Self::None | Self::Poison => {
|
||||
bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)")
|
||||
}
|
||||
}
|
||||
}
|
||||
fn has_meta(self) -> bool {
|
||||
match self {
|
||||
Self::Meta(_) => true,
|
||||
Self::None | Self::Poison => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> MemPlaceMeta<Tag> {
|
||||
pub fn erase_tag(self) -> MemPlaceMeta<()> {
|
||||
match self {
|
||||
Self::Meta(s) => MemPlaceMeta::Meta(s.erase_tag()),
|
||||
Self::None => MemPlaceMeta::None,
|
||||
Self::Poison => MemPlaceMeta::Poison,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
|
||||
pub struct MemPlace<Tag = (), Id = AllocId> {
|
||||
/// A place may have an integral pointer for ZSTs, and since it might
|
||||
|
@ -30,7 +71,7 @@ pub struct MemPlace<Tag = (), Id = AllocId> {
|
|||
/// Metadata for unsized places. Interpretation is up to the type.
|
||||
/// Must not be present for sized types, but can be missing for unsized types
|
||||
/// (e.g., `extern type`).
|
||||
pub meta: Option<Scalar<Tag, Id>>,
|
||||
pub meta: MemPlaceMeta<Tag, Id>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
|
||||
|
@ -88,21 +129,17 @@ impl<Tag> MemPlace<Tag> {
|
|||
|
||||
#[inline]
|
||||
pub fn erase_tag(self) -> MemPlace {
|
||||
MemPlace {
|
||||
ptr: self.ptr.erase_tag(),
|
||||
align: self.align,
|
||||
meta: self.meta.map(Scalar::erase_tag),
|
||||
}
|
||||
MemPlace { ptr: self.ptr.erase_tag(), align: self.align, meta: self.meta.erase_tag() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
|
||||
MemPlace { ptr, align, meta: None }
|
||||
fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
|
||||
MemPlace { ptr, align, meta: MemPlaceMeta::None }
|
||||
}
|
||||
|
||||
/// Produces a Place that will error if attempted to be read from or written to
|
||||
#[inline(always)]
|
||||
pub fn null(cx: &impl HasDataLayout) -> Self {
|
||||
fn null(cx: &impl HasDataLayout) -> Self {
|
||||
Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1).unwrap())
|
||||
}
|
||||
|
||||
|
@ -116,15 +153,19 @@ impl<Tag> MemPlace<Tag> {
|
|||
#[inline(always)]
|
||||
pub fn to_ref(self) -> Immediate<Tag> {
|
||||
match self.meta {
|
||||
None => Immediate::Scalar(self.ptr.into()),
|
||||
Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
|
||||
MemPlaceMeta::None => Immediate::Scalar(self.ptr.into()),
|
||||
MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
|
||||
MemPlaceMeta::Poison => bug!(
|
||||
"MPlaceTy::dangling may never be used to produce a \
|
||||
place that will have the address of its pointee taken"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset(
|
||||
self,
|
||||
offset: Size,
|
||||
meta: Option<Scalar<Tag>>,
|
||||
meta: MemPlaceMeta<Tag>,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> InterpResult<'tcx, Self> {
|
||||
Ok(MemPlace {
|
||||
|
@ -139,13 +180,10 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
|
|||
/// Produces a MemPlace that works for ZST but nothing else
|
||||
#[inline]
|
||||
pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
|
||||
MPlaceTy {
|
||||
mplace: MemPlace::from_scalar_ptr(
|
||||
Scalar::from_uint(layout.align.abi.bytes(), cx.pointer_size()),
|
||||
layout.align.abi,
|
||||
),
|
||||
layout,
|
||||
}
|
||||
let align = layout.align.abi;
|
||||
let ptr = Scalar::from_uint(align.bytes(), cx.pointer_size());
|
||||
// `Poison` this to make sure that the pointer value `ptr` is never observable by the program.
|
||||
MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout }
|
||||
}
|
||||
|
||||
/// Replace ptr tag, maintain vtable tag (if any)
|
||||
|
@ -158,7 +196,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
|
|||
pub fn offset(
|
||||
self,
|
||||
offset: Size,
|
||||
meta: Option<Scalar<Tag>>,
|
||||
meta: MemPlaceMeta<Tag>,
|
||||
layout: TyLayout<'tcx>,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> InterpResult<'tcx, Self> {
|
||||
|
@ -175,7 +213,9 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
|
|||
if self.layout.is_unsized() {
|
||||
// We need to consult `meta` metadata
|
||||
match self.layout.ty.kind {
|
||||
ty::Slice(..) | ty::Str => return self.mplace.meta.unwrap().to_machine_usize(cx),
|
||||
ty::Slice(..) | ty::Str => {
|
||||
return self.mplace.meta.unwrap_meta().to_machine_usize(cx);
|
||||
}
|
||||
_ => bug!("len not supported on unsized type {:?}", self.layout.ty),
|
||||
}
|
||||
} else {
|
||||
|
@ -191,7 +231,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
|
|||
#[inline]
|
||||
pub(super) fn vtable(self) -> Scalar<Tag> {
|
||||
match self.layout.ty.kind {
|
||||
ty::Dynamic(..) => self.mplace.meta.unwrap(),
|
||||
ty::Dynamic(..) => self.mplace.meta.unwrap_meta(),
|
||||
_ => bug!("vtable not supported on type {:?}", self.layout.ty),
|
||||
}
|
||||
}
|
||||
|
@ -200,36 +240,36 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
|
|||
// These are defined here because they produce a place.
|
||||
impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
|
||||
/// Note: do not call `as_ref` on the resulting place. This function should only be used to
|
||||
/// read from the resulting mplace, not to get its address back.
|
||||
pub fn try_as_mplace(
|
||||
self,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
|
||||
match *self {
|
||||
Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
|
||||
Operand::Immediate(_) if self.layout.is_zst() => {
|
||||
Ok(MPlaceTy::dangling(self.layout, cx))
|
||||
}
|
||||
Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
|
||||
self.try_as_mplace().unwrap()
|
||||
/// Note: do not call `as_ref` on the resulting place. This function should only be used to
|
||||
/// read from the resulting mplace, not to get its address back.
|
||||
pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
|
||||
self.try_as_mplace(cx).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag: ::std::fmt::Debug> Place<Tag> {
|
||||
/// Produces a Place that will error if attempted to be read from or written to
|
||||
#[inline(always)]
|
||||
pub fn null(cx: &impl HasDataLayout) -> Self {
|
||||
fn null(cx: &impl HasDataLayout) -> Self {
|
||||
Place::Ptr(MemPlace::null(cx))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
|
||||
Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
|
||||
Place::Ptr(MemPlace::from_ptr(ptr, align))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn assert_mem_place(self) -> MemPlace<Tag> {
|
||||
match self {
|
||||
|
@ -270,8 +310,10 @@ where
|
|||
val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
|
||||
let layout = self.layout_of(pointee_type)?;
|
||||
let (ptr, meta) = match *val {
|
||||
Immediate::Scalar(ptr) => (ptr.not_undef()?, None),
|
||||
Immediate::ScalarPair(ptr, meta) => (ptr.not_undef()?, Some(meta.not_undef()?)),
|
||||
Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None),
|
||||
Immediate::ScalarPair(ptr, meta) => {
|
||||
(ptr.not_undef()?, MemPlaceMeta::Meta(meta.not_undef()?))
|
||||
}
|
||||
};
|
||||
|
||||
let mplace = MemPlace {
|
||||
|
@ -305,14 +347,14 @@ where
|
|||
/// On success, returns `None` for zero-sized accesses (where nothing else is
|
||||
/// left to do) and a `Pointer` to use for the actual access otherwise.
|
||||
#[inline]
|
||||
pub fn check_mplace_access(
|
||||
pub(super) fn check_mplace_access(
|
||||
&self,
|
||||
place: MPlaceTy<'tcx, M::PointerTag>,
|
||||
size: Option<Size>,
|
||||
) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
|
||||
let size = size.unwrap_or_else(|| {
|
||||
assert!(!place.layout.is_unsized());
|
||||
assert!(place.meta.is_none());
|
||||
assert!(!place.meta.has_meta());
|
||||
place.layout.size
|
||||
});
|
||||
self.memory.check_ptr_access(place.ptr, size, place.align)
|
||||
|
@ -338,7 +380,7 @@ where
|
|||
|
||||
/// Force `place.ptr` to a `Pointer`.
|
||||
/// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
|
||||
pub fn force_mplace_ptr(
|
||||
pub(super) fn force_mplace_ptr(
|
||||
&self,
|
||||
mut place: MPlaceTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
|
@ -405,7 +447,7 @@ where
|
|||
} else {
|
||||
// base.meta could be present; we might be accessing a sized field of an unsized
|
||||
// struct.
|
||||
(None, offset)
|
||||
(MemPlaceMeta::None, offset)
|
||||
};
|
||||
|
||||
// We do not look at `base.layout.align` nor `field_layout.align`, unlike
|
||||
|
@ -415,7 +457,7 @@ where
|
|||
|
||||
// Iterates over all fields of an array. Much more efficient than doing the
|
||||
// same by repeatedly calling `mplace_array`.
|
||||
pub fn mplace_array_fields(
|
||||
pub(super) fn mplace_array_fields(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, Tag>,
|
||||
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'tcx>
|
||||
|
@ -427,10 +469,10 @@ where
|
|||
};
|
||||
let layout = base.layout.field(self, 0)?;
|
||||
let dl = &self.tcx.data_layout;
|
||||
Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
|
||||
Ok((0..len).map(move |i| base.offset(i * stride, MemPlaceMeta::None, layout, dl)))
|
||||
}
|
||||
|
||||
pub fn mplace_subslice(
|
||||
fn mplace_subslice(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
from: u64,
|
||||
|
@ -460,10 +502,10 @@ where
|
|||
let (meta, ty) = match base.layout.ty.kind {
|
||||
// It is not nice to match on the type, but that seems to be the only way to
|
||||
// implement this.
|
||||
ty::Array(inner, _) => (None, self.tcx.mk_array(inner, inner_len)),
|
||||
ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)),
|
||||
ty::Slice(..) => {
|
||||
let len = Scalar::from_uint(inner_len, self.pointer_size());
|
||||
(Some(len), base.layout.ty)
|
||||
(MemPlaceMeta::Meta(len), base.layout.ty)
|
||||
}
|
||||
_ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
|
||||
};
|
||||
|
@ -471,18 +513,18 @@ where
|
|||
base.offset(from_offset, meta, layout, self)
|
||||
}
|
||||
|
||||
pub fn mplace_downcast(
|
||||
pub(super) fn mplace_downcast(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
variant: VariantIdx,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
// Downcasts only change the layout
|
||||
assert!(base.meta.is_none());
|
||||
assert!(!base.meta.has_meta());
|
||||
Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
|
||||
}
|
||||
|
||||
/// Project into an mplace
|
||||
pub fn mplace_projection(
|
||||
pub(super) fn mplace_projection(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
proj_elem: &mir::PlaceElem<'tcx>,
|
||||
|
@ -971,7 +1013,7 @@ where
|
|||
pub fn force_allocation_maybe_sized(
|
||||
&mut self,
|
||||
place: PlaceTy<'tcx, M::PointerTag>,
|
||||
meta: Option<Scalar<M::PointerTag>>,
|
||||
meta: MemPlaceMeta<M::PointerTag>,
|
||||
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
|
||||
let (mplace, size) = match place.place {
|
||||
Place::Local { frame, local } => {
|
||||
|
@ -1016,7 +1058,7 @@ where
|
|||
&mut self,
|
||||
place: PlaceTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
Ok(self.force_allocation_maybe_sized(place, None)?.0)
|
||||
Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0)
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
|
@ -1036,8 +1078,11 @@ where
|
|||
) -> MPlaceTy<'tcx, M::PointerTag> {
|
||||
let ptr = self.memory.allocate_static_bytes(str.as_bytes(), kind);
|
||||
let meta = Scalar::from_uint(str.len() as u128, self.pointer_size());
|
||||
let mplace =
|
||||
MemPlace { ptr: ptr.into(), align: Align::from_bytes(1).unwrap(), meta: Some(meta) };
|
||||
let mplace = MemPlace {
|
||||
ptr: ptr.into(),
|
||||
align: Align::from_bytes(1).unwrap(),
|
||||
meta: MemPlaceMeta::Meta(meta),
|
||||
};
|
||||
|
||||
let layout = self.layout_of(self.tcx.mk_static_str()).unwrap();
|
||||
MPlaceTy { mplace, layout }
|
||||
|
@ -1145,7 +1190,7 @@ where
|
|||
assert_eq!(align, layout.align.abi);
|
||||
}
|
||||
|
||||
let mplace = MPlaceTy { mplace: MemPlace { meta: None, ..*mplace }, layout };
|
||||
let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout };
|
||||
Ok((instance, mplace))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@ use rustc_span::source_map::Span;
|
|||
use syntax::ast::Mutability;
|
||||
|
||||
use super::eval_context::{LocalState, StackPopCleanup};
|
||||
use super::{Frame, Immediate, LocalValue, MemPlace, Memory, Operand, Place, ScalarMaybeUndef};
|
||||
use super::{
|
||||
Frame, Immediate, LocalValue, MemPlace, MemPlaceMeta, Memory, Operand, Place, ScalarMaybeUndef,
|
||||
};
|
||||
use crate::const_eval::CompileTimeInterpreter;
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -205,6 +207,14 @@ impl_snapshot_for!(
|
|||
}
|
||||
);
|
||||
|
||||
impl_snapshot_for!(
|
||||
enum MemPlaceMeta {
|
||||
Meta(s),
|
||||
None,
|
||||
Poison,
|
||||
}
|
||||
);
|
||||
|
||||
impl_snapshot_for!(struct MemPlace {
|
||||
ptr,
|
||||
meta,
|
||||
|
|
|
@ -378,7 +378,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
None => {
|
||||
// Unsized self.
|
||||
args[0].assert_mem_place()
|
||||
args[0].assert_mem_place(self)
|
||||
}
|
||||
};
|
||||
// Find and consult vtable
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_span::symbol::{sym, Symbol};
|
|||
use std::hash::Hash;
|
||||
|
||||
use super::{
|
||||
CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Scalar,
|
||||
CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
|
||||
ValueVisitor,
|
||||
};
|
||||
|
||||
|
@ -246,13 +246,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
|
|||
|
||||
fn check_wide_ptr_meta(
|
||||
&mut self,
|
||||
meta: Option<Scalar<M::PointerTag>>,
|
||||
meta: MemPlaceMeta<M::PointerTag>,
|
||||
pointee: TyLayout<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
|
||||
match tail.kind {
|
||||
ty::Dynamic(..) => {
|
||||
let vtable = meta.unwrap();
|
||||
let vtable = meta.unwrap_meta();
|
||||
try_validation!(
|
||||
self.ecx.memory.check_ptr_access(
|
||||
vtable,
|
||||
|
@ -276,7 +276,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
|
|||
}
|
||||
ty::Slice(..) | ty::Str => {
|
||||
let _len = try_validation!(
|
||||
meta.unwrap().to_machine_usize(self.ecx),
|
||||
meta.unwrap_meta().to_machine_usize(self.ecx),
|
||||
"non-integer slice length in wide pointer",
|
||||
self.path
|
||||
);
|
||||
|
@ -571,7 +571,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||
) -> InterpResult<'tcx> {
|
||||
match op.layout.ty.kind {
|
||||
ty::Str => {
|
||||
let mplace = op.assert_mem_place(); // strings are never immediate
|
||||
let mplace = op.assert_mem_place(self.ecx); // strings are never immediate
|
||||
try_validation!(
|
||||
self.ecx.read_str(mplace),
|
||||
"uninitialized or non-UTF-8 data in str",
|
||||
|
@ -599,15 +599,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||
{
|
||||
// Optimized handling for arrays of integer/float type.
|
||||
|
||||
// bailing out for zsts is ok, since the array element type can only be int/float
|
||||
if op.layout.is_zst() {
|
||||
return Ok(());
|
||||
}
|
||||
// non-ZST array cannot be immediate, slices are never immediate
|
||||
let mplace = op.assert_mem_place();
|
||||
// Arrays cannot be immediate, slices are never immediate.
|
||||
let mplace = op.assert_mem_place(self.ecx);
|
||||
// This is the length of the array/slice.
|
||||
let len = mplace.len(self.ecx)?;
|
||||
// zero length slices have nothing to be checked
|
||||
// Zero length slices have nothing to be checked.
|
||||
if len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ macro_rules! make_value_visitor {
|
|||
match v.layout().ty.kind {
|
||||
ty::Dynamic(..) => {
|
||||
// immediate trait objects are not a thing
|
||||
let dest = v.to_op(self.ecx())?.assert_mem_place();
|
||||
let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
|
||||
let inner = self.ecx().unpack_dyn_trait(dest)?.1;
|
||||
trace!("walk_value: dyn object layout: {:#?}", inner.layout);
|
||||
// recurse with the inner type
|
||||
|
@ -292,13 +292,7 @@ macro_rules! make_value_visitor {
|
|||
},
|
||||
layout::FieldPlacement::Array { .. } => {
|
||||
// Let's get an mplace first.
|
||||
let mplace = if v.layout().is_zst() {
|
||||
// it's a ZST, the memory content cannot matter
|
||||
MPlaceTy::dangling(v.layout(), self.ecx())
|
||||
} else {
|
||||
// non-ZST array/slice/str cannot be immediate
|
||||
v.to_op(self.ecx())?.assert_mem_place()
|
||||
};
|
||||
let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
|
||||
// Now we can go over all the fields.
|
||||
let iter = self.ecx().mplace_array_fields(mplace)?
|
||||
.map(|f| f.and_then(|f| {
|
||||
|
|
|
@ -707,7 +707,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
ScalarMaybeUndef::Scalar(r),
|
||||
)) => l.is_bits() && r.is_bits(),
|
||||
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
|
||||
intern_const_alloc_recursive(&mut self.ecx, None, op.assert_mem_place())
|
||||
let mplace = op.assert_mem_place(&self.ecx);
|
||||
intern_const_alloc_recursive(&mut self.ecx, None, mplace)
|
||||
.expect("failed to intern alloc");
|
||||
true
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ impl<'a> Parser<'a> {
|
|||
self.expect_gt()?;
|
||||
(params, span_lo.to(self.prev_span))
|
||||
} else {
|
||||
(vec![], self.prev_span.between(self.token.span))
|
||||
(vec![], self.prev_span.shrink_to_hi())
|
||||
};
|
||||
Ok(ast::Generics {
|
||||
params,
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::maybe_whole;
|
|||
|
||||
use rustc_error_codes::*;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
|
||||
use rustc_span::source_map::{self, respan, Span};
|
||||
use rustc_span::source_map::{self, respan, Span, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::BytePos;
|
||||
use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
|
||||
|
@ -140,7 +140,7 @@ impl<'a> Parser<'a> {
|
|||
self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span));
|
||||
}
|
||||
let ext = self.parse_extern()?;
|
||||
self.bump(); // `fn`
|
||||
self.expect_keyword(kw::Fn)?;
|
||||
|
||||
let header = FnHeader {
|
||||
unsafety,
|
||||
|
@ -542,10 +542,11 @@ impl<'a> Parser<'a> {
|
|||
/// impl<'a, T> TYPE { /* impl items */ }
|
||||
/// impl<'a, T> TRAIT for TYPE { /* impl items */ }
|
||||
/// impl<'a, T> !TRAIT for TYPE { /* impl items */ }
|
||||
/// impl<'a, T> const TRAIT for TYPE { /* impl items */ }
|
||||
///
|
||||
/// We actually parse slightly more relaxed grammar for better error reporting and recovery.
|
||||
/// `impl` GENERICS `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}`
|
||||
/// `impl` GENERICS `!`? TYPE (`where` PREDICATES)? `{` BODY `}`
|
||||
/// `impl` GENERICS `const`? `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}`
|
||||
/// `impl` GENERICS `const`? `!`? TYPE (`where` PREDICATES)? `{` BODY `}`
|
||||
fn parse_item_impl(
|
||||
&mut self,
|
||||
unsafety: Unsafety,
|
||||
|
@ -555,7 +556,19 @@ impl<'a> Parser<'a> {
|
|||
let mut generics = if self.choose_generics_over_qpath() {
|
||||
self.parse_generics()?
|
||||
} else {
|
||||
Generics::default()
|
||||
let mut generics = Generics::default();
|
||||
// impl A for B {}
|
||||
// /\ this is where `generics.span` should point when there are no type params.
|
||||
generics.span = self.prev_span.shrink_to_hi();
|
||||
generics
|
||||
};
|
||||
|
||||
let constness = if self.eat_keyword(kw::Const) {
|
||||
let span = self.prev_span;
|
||||
self.sess.gated_spans.gate(sym::const_trait_impl, span);
|
||||
Some(respan(span, Constness::Const))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
|
||||
|
@ -618,7 +631,8 @@ impl<'a> Parser<'a> {
|
|||
err_path(ty_first.span)
|
||||
}
|
||||
};
|
||||
let trait_ref = TraitRef { path, ref_id: ty_first.id };
|
||||
let constness = constness.map(|c| c.node);
|
||||
let trait_ref = TraitRef { path, constness, ref_id: ty_first.id };
|
||||
|
||||
ItemKind::Impl(
|
||||
unsafety,
|
||||
|
@ -631,6 +645,13 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
}
|
||||
None => {
|
||||
// Reject `impl const Type {}` here
|
||||
if let Some(Spanned { node: Constness::Const, span }) = constness {
|
||||
self.struct_span_err(span, "`const` cannot modify an inherent impl")
|
||||
.help("only a trait impl can be `const`")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// impl Type
|
||||
ItemKind::Impl(
|
||||
unsafety,
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
|||
use rustc_error_codes::*;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use syntax::ast::{
|
||||
self, BareFnTy, FunctionRetTy, GenericParam, Ident, Lifetime, MutTy, Ty, TyKind,
|
||||
};
|
||||
|
@ -17,6 +17,24 @@ use syntax::ast::{Mac, Mutability};
|
|||
use syntax::ptr::P;
|
||||
use syntax::token::{self, Token};
|
||||
|
||||
/// Any `?` or `?const` modifiers that appear at the start of a bound.
|
||||
struct BoundModifiers {
|
||||
/// `?Trait`.
|
||||
maybe: Option<Span>,
|
||||
|
||||
/// `?const Trait`.
|
||||
maybe_const: Option<Span>,
|
||||
}
|
||||
|
||||
impl BoundModifiers {
|
||||
fn trait_bound_modifier(&self) -> TraitBoundModifier {
|
||||
match self.maybe {
|
||||
Some(_) => TraitBoundModifier::Maybe,
|
||||
None => TraitBoundModifier::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
|
||||
/// `IDENT<<u8 as Trait>::AssocTy>`.
|
||||
///
|
||||
|
@ -195,7 +213,9 @@ impl<'a> Parser<'a> {
|
|||
lo: Span,
|
||||
parse_plus: bool,
|
||||
) -> PResult<'a, TyKind> {
|
||||
let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
|
||||
assert_ne!(self.token, token::Question);
|
||||
|
||||
let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span));
|
||||
let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
|
||||
if parse_plus {
|
||||
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
|
||||
|
@ -421,12 +441,15 @@ impl<'a> Parser<'a> {
|
|||
let has_parens = self.eat(&token::OpenDelim(token::Paren));
|
||||
let inner_lo = self.token.span;
|
||||
let is_negative = self.eat(&token::Not);
|
||||
let question = self.eat(&token::Question).then_some(self.prev_span);
|
||||
|
||||
let modifiers = self.parse_ty_bound_modifiers();
|
||||
let bound = if self.token.is_lifetime() {
|
||||
self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?
|
||||
self.error_lt_bound_with_modifiers(modifiers);
|
||||
self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
|
||||
} else {
|
||||
self.parse_generic_ty_bound(lo, has_parens, question)?
|
||||
self.parse_generic_ty_bound(lo, has_parens, modifiers)?
|
||||
};
|
||||
|
||||
Ok(if is_negative { Err(anchor_lo.to(self.prev_span)) } else { Ok(bound) })
|
||||
}
|
||||
|
||||
|
@ -439,9 +462,7 @@ impl<'a> Parser<'a> {
|
|||
lo: Span,
|
||||
inner_lo: Span,
|
||||
has_parens: bool,
|
||||
question: Option<Span>,
|
||||
) -> PResult<'a, GenericBound> {
|
||||
self.error_opt_out_lifetime(question);
|
||||
let bound = GenericBound::Outlives(self.expect_lifetime());
|
||||
if has_parens {
|
||||
// FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
|
||||
|
@ -451,8 +472,17 @@ impl<'a> Parser<'a> {
|
|||
Ok(bound)
|
||||
}
|
||||
|
||||
fn error_opt_out_lifetime(&self, question: Option<Span>) {
|
||||
if let Some(span) = question {
|
||||
/// Emits an error if any trait bound modifiers were present.
|
||||
fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) {
|
||||
if let Some(span) = modifiers.maybe_const {
|
||||
self.struct_span_err(
|
||||
span,
|
||||
"`?const` may only modify trait bounds, not lifetime bounds",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
if let Some(span) = modifiers.maybe {
|
||||
self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds")
|
||||
.emit();
|
||||
}
|
||||
|
@ -478,25 +508,58 @@ impl<'a> Parser<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
|
||||
///
|
||||
/// If no modifiers are present, this does not consume any tokens.
|
||||
///
|
||||
/// ```
|
||||
/// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
|
||||
/// ```
|
||||
fn parse_ty_bound_modifiers(&mut self) -> BoundModifiers {
|
||||
if !self.eat(&token::Question) {
|
||||
return BoundModifiers { maybe: None, maybe_const: None };
|
||||
}
|
||||
|
||||
// `? ...`
|
||||
let first_question = self.prev_span;
|
||||
if !self.eat_keyword(kw::Const) {
|
||||
return BoundModifiers { maybe: Some(first_question), maybe_const: None };
|
||||
}
|
||||
|
||||
// `?const ...`
|
||||
let maybe_const = first_question.to(self.prev_span);
|
||||
self.sess.gated_spans.gate(sym::const_trait_bound_opt_out, maybe_const);
|
||||
if !self.eat(&token::Question) {
|
||||
return BoundModifiers { maybe: None, maybe_const: Some(maybe_const) };
|
||||
}
|
||||
|
||||
// `?const ? ...`
|
||||
let second_question = self.prev_span;
|
||||
BoundModifiers { maybe: Some(second_question), maybe_const: Some(maybe_const) }
|
||||
}
|
||||
|
||||
/// Parses a type bound according to:
|
||||
/// ```
|
||||
/// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
|
||||
/// TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
|
||||
/// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
|
||||
/// ```
|
||||
///
|
||||
/// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
|
||||
fn parse_generic_ty_bound(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
has_parens: bool,
|
||||
question: Option<Span>,
|
||||
modifiers: BoundModifiers,
|
||||
) -> PResult<'a, GenericBound> {
|
||||
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
||||
let path = self.parse_path(PathStyle::Type)?;
|
||||
if has_parens {
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
}
|
||||
let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
|
||||
let modifier = question.map_or(TraitBoundModifier::None, |_| TraitBoundModifier::Maybe);
|
||||
Ok(GenericBound::Trait(poly_trait, modifier))
|
||||
|
||||
let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst);
|
||||
let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span));
|
||||
Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier()))
|
||||
}
|
||||
|
||||
/// Optionally parses `for<$generic_params>`.
|
||||
|
|
|
@ -24,6 +24,24 @@ use syntax::walk_list;
|
|||
|
||||
use rustc_error_codes::*;
|
||||
|
||||
/// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
|
||||
#[derive(Clone, Copy)]
|
||||
enum BoundContext {
|
||||
ImplTrait,
|
||||
TraitBounds,
|
||||
TraitObject,
|
||||
}
|
||||
|
||||
impl BoundContext {
|
||||
fn description(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ImplTrait => "`impl Trait`",
|
||||
Self::TraitBounds => "supertraits",
|
||||
Self::TraitObject => "trait objects",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AstValidator<'a> {
|
||||
session: &'a Session,
|
||||
has_proc_macro_decls: bool,
|
||||
|
@ -33,6 +51,12 @@ struct AstValidator<'a> {
|
|||
/// e.g., `impl Iterator<Item = impl Debug>`.
|
||||
outer_impl_trait: Option<Span>,
|
||||
|
||||
/// Keeps track of the `BoundContext` as we recurse.
|
||||
///
|
||||
/// This is used to forbid `?const Trait` bounds in, e.g.,
|
||||
/// `impl Iterator<Item = Box<dyn ?const Trait>`.
|
||||
bound_context: Option<BoundContext>,
|
||||
|
||||
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
|
||||
/// or `Foo::Bar<impl Trait>`
|
||||
is_impl_trait_banned: bool,
|
||||
|
@ -59,10 +83,20 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.outer_impl_trait, outer);
|
||||
f(self);
|
||||
if outer.is_some() {
|
||||
self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
|
||||
} else {
|
||||
f(self)
|
||||
}
|
||||
self.outer_impl_trait = old;
|
||||
}
|
||||
|
||||
fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
|
||||
let old = self.bound_context.replace(ctx);
|
||||
f(self);
|
||||
self.bound_context = old;
|
||||
}
|
||||
|
||||
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
|
||||
match constraint.kind {
|
||||
AssocTyConstraintKind::Equality { .. } => {}
|
||||
|
@ -84,6 +118,9 @@ impl<'a> AstValidator<'a> {
|
|||
TyKind::ImplTrait(..) => {
|
||||
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
|
||||
}
|
||||
TyKind::TraitObject(..) => {
|
||||
self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
|
||||
}
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
// We allow these:
|
||||
// - `Option<impl Trait>`
|
||||
|
@ -192,6 +229,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
|
||||
fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
|
||||
for bound in bounds {
|
||||
if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
|
||||
|
@ -697,6 +735,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
self.no_questions_in_bounds(bounds, "supertraits", true);
|
||||
|
||||
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
|
||||
// context for the supertraits.
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_generics(generics);
|
||||
self.with_bound_context(BoundContext::TraitBounds, |this| {
|
||||
walk_list!(this, visit_param_bound, bounds);
|
||||
});
|
||||
walk_list!(self, visit_trait_item, trait_items);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return;
|
||||
}
|
||||
ItemKind::Mod(_) => {
|
||||
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
||||
|
@ -841,6 +891,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
visit::walk_generic_param(self, param);
|
||||
}
|
||||
|
||||
fn visit_param_bound(&mut self, bound: &'a GenericBound) {
|
||||
if let GenericBound::Trait(poly, maybe_bound) = bound {
|
||||
match poly.trait_ref.constness {
|
||||
Some(Constness::NotConst) => {
|
||||
if *maybe_bound == TraitBoundModifier::Maybe {
|
||||
self.err_handler()
|
||||
.span_err(bound.span(), "`?const` and `?` are mutually exclusive");
|
||||
}
|
||||
|
||||
if let Some(ctx) = self.bound_context {
|
||||
let msg = format!("`?const` is not permitted in {}", ctx.description());
|
||||
self.err_handler().span_err(bound.span(), &msg);
|
||||
}
|
||||
}
|
||||
|
||||
Some(Constness::Const) => bug!("Parser should reject bare `const` on bounds"),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
visit::walk_param_bound(self, bound)
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pat: &'a Pat) {
|
||||
match pat.kind {
|
||||
PatKind::Lit(ref expr) => {
|
||||
|
@ -949,6 +1022,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffe
|
|||
session,
|
||||
has_proc_macro_decls: false,
|
||||
outer_impl_trait: None,
|
||||
bound_context: None,
|
||||
is_impl_trait_banned: false,
|
||||
is_assoc_ty_bound_banned: false,
|
||||
lint_buffer: lints,
|
||||
|
|
|
@ -22,7 +22,7 @@ use Determinacy::*;
|
|||
|
||||
use errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc::hir::exports::ExportMap;
|
||||
use rustc::hir::map::Definitions;
|
||||
use rustc::hir::map::{DefKey, Definitions};
|
||||
use rustc::lint;
|
||||
use rustc::middle::cstore::{CrateStore, MetadataLoaderDyn};
|
||||
use rustc::session::Session;
|
||||
|
@ -1027,8 +1027,12 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
|
|||
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
|
||||
/// the resolver is no longer needed as all the relevant information is inline.
|
||||
impl rustc_ast_lowering::Resolver for Resolver<'_> {
|
||||
fn cstore(&self) -> &dyn CrateStore {
|
||||
self.cstore()
|
||||
fn def_key(&mut self, id: DefId) -> DefKey {
|
||||
if id.is_local() { self.definitions().def_key(id.index) } else { self.cstore().def_key(id) }
|
||||
}
|
||||
|
||||
fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
|
||||
self.cstore().item_generics_num_lifetimes(def_id, sess)
|
||||
}
|
||||
|
||||
fn resolve_str_path(
|
||||
|
|
|
@ -219,6 +219,8 @@ symbols! {
|
|||
const_raw_ptr_deref,
|
||||
const_raw_ptr_to_usize_cast,
|
||||
const_transmute,
|
||||
const_trait_bound_opt_out,
|
||||
const_trait_impl,
|
||||
contents,
|
||||
context,
|
||||
convert,
|
||||
|
|
|
@ -2803,7 +2803,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// allowed. `allow_ty_infer` gates this behavior.
|
||||
crate::collect::placeholder_type_error(
|
||||
tcx,
|
||||
ident_span.unwrap_or(DUMMY_SP),
|
||||
ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP),
|
||||
generic_params,
|
||||
visitor.0,
|
||||
ident_span.is_some(),
|
||||
|
|
|
@ -114,6 +114,7 @@ use rustc::ty::{
|
|||
self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
|
||||
ToPredicate, Ty, TyCtxt, UserType,
|
||||
};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
|
@ -146,7 +147,6 @@ use crate::lint;
|
|||
use crate::require_c_abi_if_c_variadic;
|
||||
use crate::session::config::EntryFnType;
|
||||
use crate::session::Session;
|
||||
use crate::util::captures::Captures;
|
||||
use crate::util::common::{indenter, ErrorReported};
|
||||
use crate::TypeAndSubsts;
|
||||
|
||||
|
@ -4746,14 +4746,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.join(", ");
|
||||
}
|
||||
Some(Node::Expr(hir::Expr {
|
||||
kind: ExprKind::Closure(_, _, body_id, closure_span, _),
|
||||
kind: ExprKind::Closure(_, _, body_id, _, _),
|
||||
span: full_closure_span,
|
||||
..
|
||||
})) => {
|
||||
if *full_closure_span == expr.span {
|
||||
return false;
|
||||
}
|
||||
err.span_label(*closure_span, "closure defined here");
|
||||
msg = "call this closure";
|
||||
let body = hir.body(*body_id);
|
||||
sugg_call = body
|
||||
|
|
|
@ -32,7 +32,7 @@ use rustc::ty::util::Discr;
|
|||
use rustc::ty::util::IntTypeExt;
|
||||
use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use rustc::ty::{ReprOptions, ToPredicate};
|
||||
use rustc::util::captures::Captures;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
|
@ -127,7 +127,7 @@ struct CollectItemTypesVisitor<'tcx> {
|
|||
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
|
||||
crate fn placeholder_type_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ident_span: Span,
|
||||
span: Span,
|
||||
generics: &[hir::GenericParam<'_>],
|
||||
placeholder_types: Vec<Span>,
|
||||
suggest: bool,
|
||||
|
@ -153,7 +153,14 @@ crate fn placeholder_type_error(
|
|||
let mut sugg: Vec<_> =
|
||||
placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect();
|
||||
if generics.is_empty() {
|
||||
sugg.push((ident_span.shrink_to_hi(), format!("<{}>", type_name)));
|
||||
sugg.push((span, format!("<{}>", type_name)));
|
||||
} else if let Some(arg) = generics.iter().find(|arg| match arg.name {
|
||||
hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
|
||||
_ => false,
|
||||
}) {
|
||||
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
|
||||
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
|
||||
sugg.push((arg.span, format!("{}", type_name)));
|
||||
} else {
|
||||
sugg.push((
|
||||
generics.iter().last().unwrap().span.shrink_to_hi(),
|
||||
|
@ -175,8 +182,12 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
|
|||
let (generics, suggest) = match &item.kind {
|
||||
hir::ItemKind::Union(_, generics)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Struct(_, generics) => (&generics.params[..], true),
|
||||
hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false),
|
||||
| hir::ItemKind::TraitAlias(generics, _)
|
||||
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||
| hir::ItemKind::Impl(_, _, _, generics, ..)
|
||||
| hir::ItemKind::Struct(_, generics) => (generics, true),
|
||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
|
||||
| hir::ItemKind::TyAlias(_, generics) => (generics, false),
|
||||
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
|
||||
_ => return,
|
||||
};
|
||||
|
@ -184,7 +195,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
|
|||
let mut visitor = PlaceholderHirTyCollector::default();
|
||||
visitor.visit_item(item);
|
||||
|
||||
placeholder_type_error(tcx, item.ident.span, generics, visitor.0, suggest);
|
||||
placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest);
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
||||
|
@ -1798,10 +1809,19 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
/// Whether `ty` is a type with `_` placeholders that can be infered. Used in diagnostics only to
|
||||
/// use inference to provide suggestions for the appropriate type if possible.
|
||||
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
|
||||
use hir::TyKind::*;
|
||||
match &ty.kind {
|
||||
hir::TyKind::Infer => true,
|
||||
hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_suggestable_infer_ty(ty),
|
||||
hir::TyKind::Tup(tys) => tys.iter().any(|ty| is_suggestable_infer_ty(ty)),
|
||||
Infer => true,
|
||||
Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
|
||||
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
|
||||
Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
|
||||
Def(_, generic_args) => generic_args
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
hir::GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
})
|
||||
.any(is_suggestable_infer_ty),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1033,7 +1033,7 @@ impl Expr {
|
|||
pub fn to_bound(&self) -> Option<GenericBound> {
|
||||
match &self.kind {
|
||||
ExprKind::Path(None, path) => Some(GenericBound::Trait(
|
||||
PolyTraitRef::new(Vec::new(), path.clone(), self.span),
|
||||
PolyTraitRef::new(Vec::new(), path.clone(), None, self.span),
|
||||
TraitBoundModifier::None,
|
||||
)),
|
||||
_ => None,
|
||||
|
@ -2376,6 +2376,15 @@ pub enum AttrKind {
|
|||
pub struct TraitRef {
|
||||
pub path: Path,
|
||||
pub ref_id: NodeId,
|
||||
|
||||
/// The `const` modifier, if any, that appears before this trait.
|
||||
///
|
||||
/// | | `constness` |
|
||||
/// |----------------|-----------------------------|
|
||||
/// | `Trait` | `None` |
|
||||
/// | `const Trait` | `Some(Constness::Const)` |
|
||||
/// | `?const Trait` | `Some(Constness::NotConst)` |
|
||||
pub constness: Option<Constness>,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
|
@ -2390,10 +2399,15 @@ pub struct PolyTraitRef {
|
|||
}
|
||||
|
||||
impl PolyTraitRef {
|
||||
pub fn new(generic_params: Vec<GenericParam>, path: Path, span: Span) -> Self {
|
||||
pub fn new(
|
||||
generic_params: Vec<GenericParam>,
|
||||
path: Path,
|
||||
constness: Option<Constness>,
|
||||
span: Span,
|
||||
) -> Self {
|
||||
PolyTraitRef {
|
||||
bound_generic_params: generic_params,
|
||||
trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID },
|
||||
trait_ref: TraitRef { path, constness, ref_id: DUMMY_NODE_ID },
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -909,6 +909,8 @@ pub fn check_crate(
|
|||
gate_all!(or_patterns, "or-patterns syntax is experimental");
|
||||
gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
|
||||
gate_all!(raw_ref_op, "raw address of syntax is experimental");
|
||||
gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
|
||||
gate_all!(const_trait_impl, "const trait impls are experimental");
|
||||
|
||||
// All uses of `gate_all!` below this point were added in #65742,
|
||||
// and subsequently disabled (with the non-early gating readded).
|
||||
|
|
|
@ -838,7 +838,8 @@ pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut
|
|||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
|
||||
pub fn noop_visit_trait_ref<T: MutVisitor>(tr: &mut TraitRef, vis: &mut T) {
|
||||
let TraitRef { path, ref_id, constness: _ } = tr;
|
||||
vis.visit_path(path);
|
||||
vis.visit_id(ref_id);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/dont-suggest-missing-await.rs:14:18
|
||||
|
|
||||
LL | async fn make_u32() -> u32 {
|
||||
| --- the `Output` of this `async fn`'s found opaque type
|
||||
...
|
||||
LL | take_u32(x)
|
||||
| ^ expected `u32`, found opaque type
|
||||
|
|
||||
|
|
|
@ -3,6 +3,9 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::
|
|||
|
|
||||
LL | fn is_qux<T: Qux>(t: T) { }
|
||||
| ------ --- required by this bound in `is_qux`
|
||||
LL |
|
||||
LL | async fn bar() {
|
||||
| - within this `impl std::future::Future`
|
||||
...
|
||||
LL | is_qux(bar());
|
||||
| ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo`
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await-closure.rs:16:18
|
||||
|
|
||||
LL | async fn make_u32() -> u32 {
|
||||
| --- the `Output` of this `async fn`'s found opaque type
|
||||
...
|
||||
LL | take_u32(x)
|
||||
| ^
|
||||
| |
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:13:14
|
||||
|
|
||||
LL | async fn make_u32() -> u32 {
|
||||
| --- the `Output` of this `async fn`'s found opaque type
|
||||
...
|
||||
LL | take_u32(x)
|
||||
| ^
|
||||
| |
|
||||
|
@ -13,6 +16,9 @@ LL | take_u32(x)
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:23:5
|
||||
|
|
||||
LL | async fn dummy() {}
|
||||
| - the `Output` of this `async fn`'s found opaque type
|
||||
...
|
||||
LL | dummy()
|
||||
| ^^^^^^^ expected `()`, found opaque type
|
||||
|
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/closure-reform-bad.rs:11:15
|
||||
|
|
||||
LL | let f = |s: &str| println!("{}{}", s, string);
|
||||
| ------------------------------------- the found closure
|
||||
LL | call_bare(f)
|
||||
| ^ expected fn pointer, found closure
|
||||
|
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
fn main() {}
|
||||
|
||||
#[cfg(FALSE)]
|
||||
fn container() {
|
||||
const unsafe WhereIsFerris Now() {}
|
||||
//~^ ERROR expected one of `extern` or `fn`
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
error: expected one of `extern` or `fn`, found `WhereIsFerris`
|
||||
--> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs:5:18
|
||||
|
|
||||
LL | const unsafe WhereIsFerris Now() {}
|
||||
| ^^^^^^^^^^^^^ expected one of `extern` or `fn`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fn main() {}
|
||||
|
||||
#[cfg(FALSE)]
|
||||
fn container() {
|
||||
const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
|
||||
//~^ ERROR expected `fn`
|
||||
//~| ERROR `const extern fn` definitions are unstable
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
error: expected `fn`, found `PUT_ANYTHING_YOU_WANT_HERE`
|
||||
--> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:25
|
||||
|
|
||||
LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `fn`
|
||||
|
||||
error[E0658]: `const extern fn` definitions are unstable
|
||||
--> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:5
|
||||
|
|
||||
LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64926
|
||||
= help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
|
@ -1,6 +1,11 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/extern-types-distinct-types.rs:9:5
|
||||
|
|
||||
LL | type A;
|
||||
| ------- the found foreign type
|
||||
LL | type B;
|
||||
| ------- the expected foreign type
|
||||
...
|
||||
LL | r
|
||||
| ^ expected extern type `B`, found extern type `A`
|
||||
|
|
||||
|
|
|
@ -112,6 +112,9 @@ LL | fn send<T: Send>(_: T) {}
|
|||
...
|
||||
LL | send(cycle2().clone());
|
||||
| ^^^^ `std::rc::Rc<std::string::String>` cannot be sent between threads safely
|
||||
...
|
||||
LL | fn cycle2() -> impl Clone {
|
||||
| ---------- within this `impl std::clone::Clone`
|
||||
|
|
||||
= help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
|
||||
= note: required because it appears within the type `impl std::clone::Clone`
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0277]: `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
|
||||
--> $DIR/auto-trait-leak2.rs:13:5
|
||||
|
|
||||
LL | fn before() -> impl Fn(i32) {
|
||||
| ------------ within this `impl std::ops::Fn<(i32,)>`
|
||||
...
|
||||
LL | fn send<T: Send>(_: T) {}
|
||||
| ---- ---- required by this bound in `send`
|
||||
...
|
||||
|
@ -19,6 +22,9 @@ LL | fn send<T: Send>(_: T) {}
|
|||
...
|
||||
LL | send(after());
|
||||
| ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
|
||||
...
|
||||
LL | fn after() -> impl Fn(i32) {
|
||||
| ------------ within this `impl std::ops::Fn<(i32,)>`
|
||||
|
|
||||
= help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
|
||||
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/equality2.rs:25:18
|
||||
|
|
||||
LL | fn hide<T: Foo>(x: T) -> impl Foo {
|
||||
| -------- the found opaque type
|
||||
...
|
||||
LL | let _: u32 = hide(0_u32);
|
||||
| --- ^^^^^^^^^^^ expected `u32`, found opaque type
|
||||
| |
|
||||
|
@ -12,6 +15,9 @@ LL | let _: u32 = hide(0_u32);
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/equality2.rs:31:18
|
||||
|
|
||||
LL | fn hide<T: Foo>(x: T) -> impl Foo {
|
||||
| -------- the found opaque type
|
||||
...
|
||||
LL | let _: i32 = Leak::leak(hide(0_i32));
|
||||
| --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
|
||||
| |
|
||||
|
@ -25,6 +31,12 @@ LL | let _: i32 = Leak::leak(hide(0_i32));
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/equality2.rs:38:10
|
||||
|
|
||||
LL | fn hide<T: Foo>(x: T) -> impl Foo {
|
||||
| --------
|
||||
| |
|
||||
| the expected opaque type
|
||||
| the found opaque type
|
||||
...
|
||||
LL | x = (x.1,
|
||||
| ^^^ expected `u32`, found `i32`
|
||||
|
|
||||
|
@ -34,6 +46,12 @@ LL | x = (x.1,
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/equality2.rs:41:10
|
||||
|
|
||||
LL | fn hide<T: Foo>(x: T) -> impl Foo {
|
||||
| --------
|
||||
| |
|
||||
| the expected opaque type
|
||||
| the found opaque type
|
||||
...
|
||||
LL | x.0);
|
||||
| ^^^ expected `i32`, found `u32`
|
||||
|
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-24036.rs:3:9
|
||||
|
|
||||
LL | let mut x = |c| c + 1;
|
||||
| --------- the expected closure
|
||||
LL | x = |c| c + 1;
|
||||
| ^^^^^^^^^ expected closure, found a different closure
|
||||
|
|
||||
|
|
|
@ -5,7 +5,9 @@ LL | fn bar<F:FnOnce() + Send>(_: F) { }
|
|||
| --- ---- required by this bound in `bar`
|
||||
...
|
||||
LL | bar(move|| foo(x));
|
||||
| ^^^ `std::rc::Rc<usize>` cannot be sent between threads safely
|
||||
| ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`
|
||||
| |
|
||||
| `std::rc::Rc<usize>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<usize>`
|
||||
= note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
--> $DIR/no-send-res-ports.rs:29:5
|
||||
|
|
||||
LL | thread::spawn(move|| {
|
||||
| ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
LL | thread::spawn(move|| {
|
||||
| _____^^^^^^^^^^^^^_-
|
||||
| | |
|
||||
| | `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
LL | |
|
||||
LL | | let y = x;
|
||||
LL | | println!("{:?}", y);
|
||||
LL | | });
|
||||
| |_____- within this `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]`
|
||||
|
|
||||
::: $SRC_DIR/libstd/thread/mod.rs:LL:COL
|
||||
|
|
||||
LL | F: Send + 'static,
|
||||
| ---- required by this bound in `std::thread::spawn`
|
||||
LL | F: Send + 'static,
|
||||
| ---- required by this bound in `std::thread::spawn`
|
||||
|
|
||||
= help: within `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
|
||||
= note: required because it appears within the type `Port<()>`
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
error[E0277]: the trait bound `S: std::clone::Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
|
||||
--> $DIR/not-clone-closure.rs:11:23
|
||||
|
|
||||
LL | let hello = hello.clone();
|
||||
| ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S`
|
||||
LL | let hello = move || {
|
||||
| _________________-
|
||||
LL | | println!("Hello {}", a.0);
|
||||
LL | | };
|
||||
| |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
|
||||
LL |
|
||||
LL | let hello = hello.clone();
|
||||
| ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S`
|
||||
|
|
||||
= note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@ struct S<
|
|||
T: ?for<'a> Trait, // OK
|
||||
T: Tr +, // OK
|
||||
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
|
||||
|
||||
T: ?const Tr, // OK
|
||||
T: ?const ?Tr, // OK
|
||||
T: ?const Tr + 'a, // OK
|
||||
T: ?const 'a, //~ ERROR `?const` may only modify trait bounds, not lifetime bounds
|
||||
>;
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -4,5 +4,11 @@ error: `?` may only modify trait bounds, not lifetime bounds
|
|||
LL | T: ?'a,
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: `?const` may only modify trait bounds, not lifetime bounds
|
||||
--> $DIR/bounds-type.rs:15:8
|
||||
|
|
||||
LL | T: ?const 'a,
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/feature-gate.rs:11:29
|
||||
|
|
||||
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// revisions: stock gated
|
||||
// gate-test-const_trait_bound_opt_out
|
||||
|
||||
#![cfg_attr(gated, feature(const_trait_bound_opt_out))]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait T {
|
||||
const CONST: i32;
|
||||
}
|
||||
|
||||
const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
//[stock]~^ ERROR `?const` on trait bounds is experimental
|
||||
//[stock,gated]~^^ ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,18 @@
|
|||
error[E0658]: `?const` on trait bounds is experimental
|
||||
--> $DIR/feature-gate.rs:11:29
|
||||
|
|
||||
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/67794
|
||||
= help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/feature-gate.rs:11:29
|
||||
|
|
||||
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
|
@ -0,0 +1,25 @@
|
|||
#![feature(const_trait_bound_opt_out)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait T {}
|
||||
struct S;
|
||||
impl T for S {}
|
||||
|
||||
fn rpit() -> impl ?const T { S }
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn apit(_: impl ?const T) {}
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,50 @@
|
|||
error: `?const` is not permitted in `impl Trait`
|
||||
--> $DIR/in-impl-trait.rs:9:19
|
||||
|
|
||||
LL | fn rpit() -> impl ?const T { S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in `impl Trait`
|
||||
--> $DIR/in-impl-trait.rs:13:17
|
||||
|
|
||||
LL | fn apit(_: impl ?const T) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in `impl Trait`
|
||||
--> $DIR/in-impl-trait.rs:17:50
|
||||
|
|
||||
LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in `impl Trait`
|
||||
--> $DIR/in-impl-trait.rs:21:48
|
||||
|
|
||||
LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:9:19
|
||||
|
|
||||
LL | fn rpit() -> impl ?const T { S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:13:17
|
||||
|
|
||||
LL | fn apit(_: impl ?const T) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:17:50
|
||||
|
|
||||
LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:21:48
|
||||
|
|
||||
LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Super {}
|
||||
trait T: ?const Super {}
|
||||
//~^ ERROR `?const` is not permitted in supertraits
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,14 @@
|
|||
error: `?const` is not permitted in supertraits
|
||||
--> $DIR/in-trait-bounds.rs:5:10
|
||||
|
|
||||
LL | trait T: ?const Super {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-bounds.rs:5:10
|
||||
|
|
||||
LL | trait T: ?const Super {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(bare_trait_objects)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S;
|
||||
trait T {}
|
||||
impl T for S {}
|
||||
|
||||
// An inherent impl for the trait object `?const T`.
|
||||
impl ?const T {}
|
||||
//~^ ERROR `?const` is not permitted in trait objects
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn trait_object() -> &'static dyn ?const T { &S }
|
||||
//~^ ERROR `?const` is not permitted in trait objects
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
|
||||
//~^ ERROR `?const` is not permitted in trait objects
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,38 @@
|
|||
error: `?const` is not permitted in trait objects
|
||||
--> $DIR/in-trait-object.rs:10:6
|
||||
|
|
||||
LL | impl ?const T {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in trait objects
|
||||
--> $DIR/in-trait-object.rs:14:35
|
||||
|
|
||||
LL | fn trait_object() -> &'static dyn ?const T { &S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in trait objects
|
||||
--> $DIR/in-trait-object.rs:18:61
|
||||
|
|
||||
LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-object.rs:10:6
|
||||
|
|
||||
LL | impl ?const T {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-object.rs:14:35
|
||||
|
|
||||
LL | fn trait_object() -> &'static dyn ?const T { &S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-object.rs:18:61
|
||||
|
|
||||
LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// compile-flags: -Z parse-only
|
||||
|
||||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T: ?const ?const Tr>;
|
||||
//~^ ERROR expected identifier, found keyword `const`
|
||||
//~| ERROR expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`
|
|
@ -0,0 +1,14 @@
|
|||
error: expected identifier, found keyword `const`
|
||||
--> $DIR/opt-out-twice.rs:6:21
|
||||
|
|
||||
LL | struct S<T: ?const ?const Tr>;
|
||||
| ^^^^^ expected identifier, found keyword
|
||||
|
||||
error: expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`, found `Tr`
|
||||
--> $DIR/opt-out-twice.rs:6:27
|
||||
|
|
||||
LL | struct S<T: ?const ?const Tr>;
|
||||
| ^^ expected one of 7 possible tokens
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// compile-flags: -Z parse-only
|
||||
// check-pass
|
||||
|
||||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<
|
||||
T: ?const ?for<'a> Tr<'a> + 'static + ?const std::ops::Add,
|
||||
T: ?const ?for<'a: 'b> m::Trait<'a>,
|
||||
>;
|
|
@ -0,0 +1,8 @@
|
|||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
|
||||
//~^ ERROR `?const` and `?` are mutually exclusive
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,14 @@
|
|||
error: `?const` and `?` are mutually exclusive
|
||||
--> $DIR/with-maybe-sized.rs:4:13
|
||||
|
|
||||
LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/with-maybe-sized.rs:4:13
|
||||
|
|
||||
LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// compile-flags: -Z parse-only
|
||||
|
||||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S<T: const Tr>;
|
||||
//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path
|
|
@ -0,0 +1,8 @@
|
|||
error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path, found keyword `const`
|
||||
--> $DIR/without-question-mark.rs:6:13
|
||||
|
|
||||
LL | struct S<T: const Tr>;
|
||||
| ^^^^^ expected one of 9 possible tokens
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: const trait impls are not yet implemented
|
||||
--> $DIR/feature-gate.rs:9:1
|
||||
|
|
||||
LL | impl const T for S {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
13
src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs
Normal file
13
src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
// revisions: stock gated
|
||||
// gate-test-const_trait_impl
|
||||
|
||||
#![cfg_attr(gated, feature(const_trait_impl))]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S;
|
||||
trait T {}
|
||||
impl const T for S {}
|
||||
//[stock]~^ ERROR const trait impls are experimental
|
||||
//[stock,gated]~^^ ERROR const trait impls are not yet implemented
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,18 @@
|
|||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/feature-gate.rs:9:6
|
||||
|
|
||||
LL | impl const T for S {}
|
||||
| ^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/67792
|
||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
|
||||
error: const trait impls are not yet implemented
|
||||
--> $DIR/feature-gate.rs:9:1
|
||||
|
|
||||
LL | impl const T for S {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
11
src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs
Normal file
11
src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#![feature(const_trait_bound_opt_out)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S;
|
||||
trait T {}
|
||||
|
||||
impl ?const T for S {}
|
||||
//~^ ERROR expected a trait, found type
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,8 @@
|
|||
error: expected a trait, found type
|
||||
--> $DIR/impl-opt-out-trait.rs:8:6
|
||||
|
|
||||
LL | impl ?const T for S {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
14
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs
Normal file
14
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// compile-flags: -Z parse-only
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(incomplete_features)]
|
||||
#![allow(bare_trait_objects)]
|
||||
|
||||
struct S;
|
||||
trait T {}
|
||||
|
||||
impl const T {}
|
||||
//~^ ERROR `const` cannot modify an inherent impl
|
||||
|
||||
fn main() {}
|
10
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
Normal file
10
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
error: `const` cannot modify an inherent impl
|
||||
--> $DIR/inherent-impl.rs:11:6
|
||||
|
|
||||
LL | impl const T {}
|
||||
| ^^^^^
|
||||
|
|
||||
= help: only a trait impl can be `const`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
9
src/test/ui/rfc-2632-const-trait-impl/syntax.rs
Normal file
9
src/test/ui/rfc-2632-const-trait-impl/syntax.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// compile-flags: -Z parse-only
|
||||
// check-pass
|
||||
|
||||
#![feature(const_trait_bound_opt_out)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// For now, this parses since an error does not occur until AST lowering.
|
||||
impl ?const T {}
|
|
@ -236,7 +236,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/fn-or-tuple-struct-without-args.rs:46:20
|
||||
|
|
||||
LL | let closure = || 42;
|
||||
| -- closure defined here
|
||||
| ----- the found closure
|
||||
LL | let _: usize = closure;
|
||||
| ----- ^^^^^^^
|
||||
| | |
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/opaque-type-error.rs:20:9
|
||||
|
|
||||
LL | fn thing_two() -> impl Future<Output = Result<(), ()>> {
|
||||
| ------------------------------------ the found opaque type
|
||||
...
|
||||
LL | / if true {
|
||||
LL | | thing_one()
|
||||
| | ----------- expected because of this
|
||||
|
|
|
@ -11,6 +11,9 @@ LL | let z: i32 = x;
|
|||
| --- ^ expected `i32`, found opaque type
|
||||
| |
|
||||
| expected due to this
|
||||
...
|
||||
LL | type WrongGeneric<T> = impl 'static;
|
||||
| ------------------------------------ the found opaque type
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found opaque type `WrongGeneric::<&{integer}>`
|
||||
|
|
|
@ -11,6 +11,9 @@ LL | let z: i32 = x;
|
|||
| --- ^ expected `i32`, found opaque type
|
||||
| |
|
||||
| expected due to this
|
||||
...
|
||||
LL | type WrongGeneric<T> = impl 'static;
|
||||
| ------------------------------------ the found opaque type
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found opaque type `WrongGeneric::<&{integer}>`
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/never_reveal_concrete_type.rs:13:27
|
||||
|
|
||||
LL | type NoReveal = impl std::fmt::Debug;
|
||||
| ------------------------------------- the found opaque type
|
||||
...
|
||||
LL | let _: &'static str = x;
|
||||
| ------------ ^ expected `&str`, found opaque type
|
||||
| |
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/no_revealing_outside_defining_module.rs:15:19
|
||||
|
|
||||
LL | pub type Boo = impl ::std::fmt::Debug;
|
||||
| -------------------------------------- the found opaque type
|
||||
...
|
||||
LL | let _: &str = bomp();
|
||||
| ---- ^^^^^^ expected `&str`, found opaque type
|
||||
| |
|
||||
|
@ -12,6 +15,9 @@ LL | let _: &str = bomp();
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/no_revealing_outside_defining_module.rs:19:5
|
||||
|
|
||||
LL | pub type Boo = impl ::std::fmt::Debug;
|
||||
| -------------------------------------- the expected opaque type
|
||||
...
|
||||
LL | fn bomp() -> boo::Boo {
|
||||
| -------- expected `Boo` because of return type
|
||||
LL | ""
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![feature(type_alias_impl_trait)] // Needed for single test `type Y = impl Trait<_>`
|
||||
// This test checks that it is not possible to enable global type
|
||||
// inference by using the `_` type placeholder.
|
||||
|
||||
|
@ -42,6 +43,16 @@ impl Test9 {
|
|||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
}
|
||||
|
||||
fn test11(x: &usize) -> &_ {
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
&x
|
||||
}
|
||||
|
||||
unsafe fn test12(x: *const usize) -> *const *const _ {
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
&x
|
||||
}
|
||||
|
||||
impl Clone for Test9 {
|
||||
fn clone(&self) -> _ { Test9 }
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
@ -131,3 +142,37 @@ trait T {
|
|||
fn assoc_fn_test3() -> _;
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
}
|
||||
|
||||
struct BadStruct<_>(_);
|
||||
//~^ ERROR expected identifier, found reserved identifier `_`
|
||||
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
trait BadTrait<_> {}
|
||||
//~^ ERROR expected identifier, found reserved identifier `_`
|
||||
impl BadTrait<_> for BadStruct<_> {}
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
fn impl_trait() -> impl BadTrait<_> {
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
struct BadStruct1<_, _>(_);
|
||||
//~^ ERROR expected identifier, found reserved identifier `_`
|
||||
//~| ERROR expected identifier, found reserved identifier `_`
|
||||
//~| ERROR the name `_` is already used
|
||||
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
struct BadStruct2<_, T>(_, T);
|
||||
//~^ ERROR expected identifier, found reserved identifier `_`
|
||||
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
type X = Box<_>;
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
struct Struct;
|
||||
trait Trait<T> {}
|
||||
impl Trait<usize> for Struct {}
|
||||
type Y = impl Trait<_>;
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
fn foo() -> Y {
|
||||
Struct
|
||||
}
|
||||
|
|
|
@ -1,5 +1,43 @@
|
|||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/typeck_type_placeholder_item.rs:146:18
|
||||
|
|
||||
LL | struct BadStruct<_>(_);
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/typeck_type_placeholder_item.rs:149:16
|
||||
|
|
||||
LL | trait BadTrait<_> {}
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/typeck_type_placeholder_item.rs:159:19
|
||||
|
|
||||
LL | struct BadStruct1<_, _>(_);
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/typeck_type_placeholder_item.rs:159:22
|
||||
|
|
||||
LL | struct BadStruct1<_, _>(_);
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/typeck_type_placeholder_item.rs:164:19
|
||||
|
|
||||
LL | struct BadStruct2<_, T>(_, T);
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters
|
||||
--> $DIR/typeck_type_placeholder_item.rs:159:22
|
||||
|
|
||||
LL | struct BadStruct1<_, _>(_);
|
||||
| - ^ already used
|
||||
| |
|
||||
| first use of `_`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:4:14
|
||||
--> $DIR/typeck_type_placeholder_item.rs:5:14
|
||||
|
|
||||
LL | fn test() -> _ { 5 }
|
||||
| ^
|
||||
|
@ -8,7 +46,7 @@ LL | fn test() -> _ { 5 }
|
|||
| help: replace with the correct return type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:7:16
|
||||
--> $DIR/typeck_type_placeholder_item.rs:8:16
|
||||
|
|
||||
LL | fn test2() -> (_, _) { (5, 5) }
|
||||
| -^--^-
|
||||
|
@ -18,7 +56,7 @@ LL | fn test2() -> (_, _) { (5, 5) }
|
|||
| help: replace with the correct return type: `(i32, i32)`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:10:15
|
||||
--> $DIR/typeck_type_placeholder_item.rs:11:15
|
||||
|
|
||||
LL | static TEST3: _ = "test";
|
||||
| ^
|
||||
|
@ -27,7 +65,7 @@ LL | static TEST3: _ = "test";
|
|||
| help: replace `_` with the correct type: `&'static str`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:13:15
|
||||
--> $DIR/typeck_type_placeholder_item.rs:14:15
|
||||
|
|
||||
LL | static TEST4: _ = 145;
|
||||
| ^
|
||||
|
@ -36,13 +74,13 @@ LL | static TEST4: _ = 145;
|
|||
| help: replace `_` with the correct type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:16:15
|
||||
--> $DIR/typeck_type_placeholder_item.rs:17:15
|
||||
|
|
||||
LL | static TEST5: (_, _) = (1, 2);
|
||||
| ^^^^^^ not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:19:13
|
||||
--> $DIR/typeck_type_placeholder_item.rs:20:13
|
||||
|
|
||||
LL | fn test6(_: _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -53,7 +91,7 @@ LL | fn test6<T>(_: T) { }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:22:18
|
||||
--> $DIR/typeck_type_placeholder_item.rs:23:18
|
||||
|
|
||||
LL | fn test6_b<T>(_: _, _: T) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -64,7 +102,7 @@ LL | fn test6_b<T, K>(_: K, _: T) { }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:25:30
|
||||
--> $DIR/typeck_type_placeholder_item.rs:26:30
|
||||
|
|
||||
LL | fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -75,7 +113,7 @@ LL | fn test6_c<T, K, L, A, B, C>(_: C, _: (T, K, L, A, B)) { }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:28:13
|
||||
--> $DIR/typeck_type_placeholder_item.rs:29:13
|
||||
|
|
||||
LL | fn test7(x: _) { let _x: usize = x; }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -86,13 +124,13 @@ LL | fn test7<T>(x: T) { let _x: usize = x; }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:31:22
|
||||
--> $DIR/typeck_type_placeholder_item.rs:32:22
|
||||
|
|
||||
LL | fn test8(_f: fn() -> _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:31:22
|
||||
--> $DIR/typeck_type_placeholder_item.rs:32:22
|
||||
|
|
||||
LL | fn test8(_f: fn() -> _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -103,7 +141,25 @@ LL | fn test8<T>(_f: fn() -> T) { }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:54:8
|
||||
--> $DIR/typeck_type_placeholder_item.rs:46:26
|
||||
|
|
||||
LL | fn test11(x: &usize) -> &_ {
|
||||
| -^
|
||||
| ||
|
||||
| |not allowed in type signatures
|
||||
| help: replace with the correct return type: `&&usize`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:51:52
|
||||
|
|
||||
LL | unsafe fn test12(x: *const usize) -> *const *const _ {
|
||||
| --------------^
|
||||
| | |
|
||||
| | not allowed in type signatures
|
||||
| help: replace with the correct return type: `*const *const usize`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:65:8
|
||||
|
|
||||
LL | a: _,
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -122,7 +178,7 @@ LL | b: (T, T),
|
|||
|
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:60:21
|
||||
--> $DIR/typeck_type_placeholder_item.rs:71:21
|
||||
|
|
||||
LL | fn fn_test() -> _ { 5 }
|
||||
| ^
|
||||
|
@ -131,7 +187,7 @@ LL | fn fn_test() -> _ { 5 }
|
|||
| help: replace with the correct return type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:63:23
|
||||
--> $DIR/typeck_type_placeholder_item.rs:74:23
|
||||
|
|
||||
LL | fn fn_test2() -> (_, _) { (5, 5) }
|
||||
| -^--^-
|
||||
|
@ -141,7 +197,7 @@ LL | fn fn_test2() -> (_, _) { (5, 5) }
|
|||
| help: replace with the correct return type: `(i32, i32)`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:66:22
|
||||
--> $DIR/typeck_type_placeholder_item.rs:77:22
|
||||
|
|
||||
LL | static FN_TEST3: _ = "test";
|
||||
| ^
|
||||
|
@ -150,7 +206,7 @@ LL | static FN_TEST3: _ = "test";
|
|||
| help: replace `_` with the correct type: `&'static str`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:69:22
|
||||
--> $DIR/typeck_type_placeholder_item.rs:80:22
|
||||
|
|
||||
LL | static FN_TEST4: _ = 145;
|
||||
| ^
|
||||
|
@ -159,13 +215,13 @@ LL | static FN_TEST4: _ = 145;
|
|||
| help: replace `_` with the correct type: `i32`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:72:22
|
||||
--> $DIR/typeck_type_placeholder_item.rs:83:22
|
||||
|
|
||||
LL | static FN_TEST5: (_, _) = (1, 2);
|
||||
| ^^^^^^ not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:75:20
|
||||
--> $DIR/typeck_type_placeholder_item.rs:86:20
|
||||
|
|
||||
LL | fn fn_test6(_: _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -176,7 +232,7 @@ LL | fn fn_test6<T>(_: T) { }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:78:20
|
||||
--> $DIR/typeck_type_placeholder_item.rs:89:20
|
||||
|
|
||||
LL | fn fn_test7(x: _) { let _x: usize = x; }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -187,13 +243,13 @@ LL | fn fn_test7<T>(x: T) { let _x: usize = x; }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:81:29
|
||||
--> $DIR/typeck_type_placeholder_item.rs:92:29
|
||||
|
|
||||
LL | fn fn_test8(_f: fn() -> _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:81:29
|
||||
--> $DIR/typeck_type_placeholder_item.rs:92:29
|
||||
|
|
||||
LL | fn fn_test8(_f: fn() -> _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -204,7 +260,7 @@ LL | fn fn_test8<T>(_f: fn() -> T) { }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:104:12
|
||||
--> $DIR/typeck_type_placeholder_item.rs:115:12
|
||||
|
|
||||
LL | a: _,
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -223,13 +279,13 @@ LL | b: (T, T),
|
|||
|
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/typeck_type_placeholder_item.rs:109:27
|
||||
--> $DIR/typeck_type_placeholder_item.rs:120:27
|
||||
|
|
||||
LL | fn fn_test11(_: _) -> (_, _) { panic!() }
|
||||
| ^^^^^^ cannot infer type
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:109:28
|
||||
--> $DIR/typeck_type_placeholder_item.rs:120:28
|
||||
|
|
||||
LL | fn fn_test11(_: _) -> (_, _) { panic!() }
|
||||
| ^ ^ not allowed in type signatures
|
||||
|
@ -237,7 +293,7 @@ LL | fn fn_test11(_: _) -> (_, _) { panic!() }
|
|||
| not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:113:30
|
||||
--> $DIR/typeck_type_placeholder_item.rs:124:30
|
||||
|
|
||||
LL | fn fn_test12(x: i32) -> (_, _) { (x, x) }
|
||||
| -^--^-
|
||||
|
@ -247,7 +303,7 @@ LL | fn fn_test12(x: i32) -> (_, _) { (x, x) }
|
|||
| help: replace with the correct return type: `(i32, i32)`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:116:33
|
||||
--> $DIR/typeck_type_placeholder_item.rs:127:33
|
||||
|
|
||||
LL | fn fn_test13(x: _) -> (i32, _) { (x, x) }
|
||||
| ------^-
|
||||
|
@ -256,7 +312,76 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) }
|
|||
| help: replace with the correct return type: `(i32, i32)`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:121:31
|
||||
--> $DIR/typeck_type_placeholder_item.rs:146:21
|
||||
|
|
||||
LL | struct BadStruct<_>(_);
|
||||
| ^ not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | struct BadStruct<T>(T);
|
||||
| ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:151:15
|
||||
|
|
||||
LL | impl BadTrait<_> for BadStruct<_> {}
|
||||
| ^ ^ not allowed in type signatures
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | impl<T> BadTrait<T> for BadStruct<T> {}
|
||||
| ^^^ ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:154:34
|
||||
|
|
||||
LL | fn impl_trait() -> impl BadTrait<_> {
|
||||
| ^ not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:159:25
|
||||
|
|
||||
LL | struct BadStruct1<_, _>(_);
|
||||
| ^ not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | struct BadStruct1<T, _>(T);
|
||||
| ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:164:25
|
||||
|
|
||||
LL | struct BadStruct2<_, T>(_, T);
|
||||
| ^ not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | struct BadStruct2<K, T>(K, T);
|
||||
| ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:168:14
|
||||
|
|
||||
LL | type X = Box<_>;
|
||||
| ^ not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:42:27
|
||||
|
|
||||
LL | fn test10(&self, _x : _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | fn test10<T>(&self, _x : T) { }
|
||||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:132:31
|
||||
|
|
||||
LL | fn method_test1(&self, x: _);
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -267,7 +392,7 @@ LL | fn method_test1<T>(&self, x: T);
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:123:31
|
||||
--> $DIR/typeck_type_placeholder_item.rs:134:31
|
||||
|
|
||||
LL | fn method_test2(&self, x: _) -> _;
|
||||
| ^ ^ not allowed in type signatures
|
||||
|
@ -280,7 +405,7 @@ LL | fn method_test2<T>(&self, x: T) -> T;
|
|||
| ^^^ ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:125:31
|
||||
--> $DIR/typeck_type_placeholder_item.rs:136:31
|
||||
|
|
||||
LL | fn method_test3(&self) -> _;
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -291,7 +416,7 @@ LL | fn method_test3<T>(&self) -> T;
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:127:26
|
||||
--> $DIR/typeck_type_placeholder_item.rs:138:26
|
||||
|
|
||||
LL | fn assoc_fn_test1(x: _);
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -302,7 +427,7 @@ LL | fn assoc_fn_test1<T>(x: T);
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:129:26
|
||||
--> $DIR/typeck_type_placeholder_item.rs:140:26
|
||||
|
|
||||
LL | fn assoc_fn_test2(x: _) -> _;
|
||||
| ^ ^ not allowed in type signatures
|
||||
|
@ -315,7 +440,7 @@ LL | fn assoc_fn_test2<T>(x: T) -> T;
|
|||
| ^^^ ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:131:28
|
||||
--> $DIR/typeck_type_placeholder_item.rs:142:28
|
||||
|
|
||||
LL | fn assoc_fn_test3() -> _;
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -326,36 +451,7 @@ LL | fn assoc_fn_test3<T>() -> T;
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:38:24
|
||||
|
|
||||
LL | fn test9(&self) -> _ { () }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `()`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:41:27
|
||||
|
|
||||
LL | fn test10(&self, _x : _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | fn test10<T>(&self, _x : T) { }
|
||||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:46:24
|
||||
|
|
||||
LL | fn clone(&self) -> _ { Test9 }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `Test9`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:49:37
|
||||
--> $DIR/typeck_type_placeholder_item.rs:60:37
|
||||
|
|
||||
LL | fn clone_from(&mut self, other: _) { *self = Test9; }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -366,16 +462,7 @@ LL | fn clone_from<T>(&mut self, other: T) { *self = Test9; }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:88:31
|
||||
|
|
||||
LL | fn fn_test9(&self) -> _ { () }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `()`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:91:34
|
||||
--> $DIR/typeck_type_placeholder_item.rs:102:34
|
||||
|
|
||||
LL | fn fn_test10(&self, _x : _) { }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -386,16 +473,7 @@ LL | fn fn_test10<T>(&self, _x : T) { }
|
|||
| ^^^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:96:28
|
||||
|
|
||||
LL | fn clone(&self) -> _ { FnTest9 }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `main::FnTest9`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:99:41
|
||||
--> $DIR/typeck_type_placeholder_item.rs:110:41
|
||||
|
|
||||
LL | fn clone_from(&mut self, other: _) { *self = FnTest9; }
|
||||
| ^ not allowed in type signatures
|
||||
|
@ -405,7 +483,49 @@ help: use type parameters instead
|
|||
LL | fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
|
||||
| ^^^ ^
|
||||
|
||||
error: aborting due to 40 previous errors
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:174:21
|
||||
|
|
||||
LL | type Y = impl Trait<_>;
|
||||
| ^ not allowed in type signatures
|
||||
|
||||
Some errors have detailed explanations: E0121, E0282.
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:39:24
|
||||
|
|
||||
LL | fn test9(&self) -> _ { () }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `()`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:57:24
|
||||
|
|
||||
LL | fn clone(&self) -> _ { Test9 }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `Test9`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:99:31
|
||||
|
|
||||
LL | fn fn_test9(&self) -> _ { () }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `()`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:107:28
|
||||
|
|
||||
LL | fn clone(&self) -> _ { FnTest9 }
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `main::FnTest9`
|
||||
|
||||
error: aborting due to 55 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0121, E0282, E0403.
|
||||
For more information about an error, try `rustc --explain E0121`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue