Auto merge of #57428 - alexreg:associated_type_bounds, r=nikomatsakis,Centril
Implementation of RFC 2289 (associated_type_bounds) This PR implements the [`asociated_type_bounds` feature](https://github.com/rust-lang/rfcs/blob/master/text/2289-associated-type-bounds.md). Associated type bounds are implemented in: - function/method arguments and return types - structs, enums, unions - associated items in traits - type aliases - type parameter defaults - trait objects - let bindings CC @nikomatsakis @centril
This commit is contained in:
commit
740668dbd9
116 changed files with 4846 additions and 1054 deletions
|
|
@ -1351,7 +1351,7 @@ impl<'b> BorrowRefMut<'b> {
|
|||
}
|
||||
}
|
||||
|
||||
// Clone a `BorrowRefMut`.
|
||||
// Clones a `BorrowRefMut`.
|
||||
//
|
||||
// This is only valid if each `BorrowRefMut` is used to track a mutable
|
||||
// reference to a distinct, nonoverlapping range of the original object.
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
|
|||
|
||||
/// This is used for object safety, to check that a method's receiver type can be dispatched on.
|
||||
///
|
||||
/// example impl:
|
||||
/// An example implementation of the trait:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(dispatch_from_dyn, unsize)]
|
||||
|
|
|
|||
|
|
@ -674,7 +674,14 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
type_binding: &'v TypeBinding) {
|
||||
visitor.visit_id(type_binding.hir_id);
|
||||
visitor.visit_ident(type_binding.ident);
|
||||
visitor.visit_ty(&type_binding.ty);
|
||||
match type_binding.kind {
|
||||
TypeBindingKind::Equality { ref ty } => {
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
TypeBindingKind::Constraint { ref bounds } => {
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||
|
|
@ -934,7 +941,6 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'
|
|||
visitor.visit_defaultness(defaultness);
|
||||
}
|
||||
|
||||
|
||||
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
|
||||
if let Some(ctor_hir_id) = struct_definition.ctor_hir_id() {
|
||||
visitor.visit_id(ctor_hir_id);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
//! 'folding' an existing one), then you create a new ID using `next_id()`.
|
||||
//!
|
||||
//! You must ensure that IDs are unique. That means that you should only use the
|
||||
//! ID from an AST node in a single HIR node (you can assume that AST node IDs
|
||||
//! ID from an AST node in a single HIR node (you can assume that AST node-IDs
|
||||
//! are unique). Every new node must have a unique ID. Avoid cloning HIR nodes.
|
||||
//! If you do, you must then set the new node's ID to a fresh one.
|
||||
//!
|
||||
|
|
@ -69,7 +69,7 @@ use syntax::symbol::{kw, sym, Symbol};
|
|||
use syntax::tokenstream::{TokenStream, TokenTree};
|
||||
use syntax::parse::token::Token;
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::{edition, Span};
|
||||
use syntax_pos::{DUMMY_SP, edition, Span};
|
||||
|
||||
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
|
||||
|
||||
|
|
@ -106,6 +106,7 @@ pub struct LoweringContext<'a> {
|
|||
loop_scopes: Vec<NodeId>,
|
||||
is_in_loop_condition: bool,
|
||||
is_in_trait_impl: bool,
|
||||
is_in_dyn_type: bool,
|
||||
|
||||
/// What to do when we encounter either an "anonymous lifetime
|
||||
/// reference". The term "anonymous" is meant to encompass both
|
||||
|
|
@ -175,6 +176,8 @@ pub trait Resolver {
|
|||
) -> hir::Path;
|
||||
}
|
||||
|
||||
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
|
||||
/// and if so, what meaning it has.
|
||||
#[derive(Debug)]
|
||||
enum ImplTraitContext<'a> {
|
||||
/// Treat `impl Trait` as shorthand for a new universal generic parameter.
|
||||
|
|
@ -189,18 +192,21 @@ enum ImplTraitContext<'a> {
|
|||
/// equivalent to a fresh existential parameter like `existential type T; fn foo() -> T`.
|
||||
///
|
||||
/// We optionally store a `DefId` for the parent item here so we can look up necessary
|
||||
/// information later. It is `None` when no information about the context should be stored,
|
||||
/// e.g., for consts and statics.
|
||||
Existential(Option<DefId>),
|
||||
/// information later. It is `None` when no information about the context should be stored
|
||||
/// (e.g., for consts and statics).
|
||||
Existential(Option<DefId> /* fn def-ID */),
|
||||
|
||||
/// `impl Trait` is not accepted in this position.
|
||||
Disallowed(ImplTraitPosition),
|
||||
}
|
||||
|
||||
/// Position in which `impl Trait` is disallowed. Used for error reporting.
|
||||
/// Position in which `impl Trait` is disallowed.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum ImplTraitPosition {
|
||||
/// Disallowed in `let` / `const` / `static` bindings.
|
||||
Binding,
|
||||
|
||||
/// All other posiitons.
|
||||
Other,
|
||||
}
|
||||
|
||||
|
|
@ -214,7 +220,7 @@ impl<'a> ImplTraitContext<'a> {
|
|||
use self::ImplTraitContext::*;
|
||||
match self {
|
||||
Universal(params) => Universal(params),
|
||||
Existential(did) => Existential(*did),
|
||||
Existential(fn_def_id) => Existential(*fn_def_id),
|
||||
Disallowed(pos) => Disallowed(*pos),
|
||||
}
|
||||
}
|
||||
|
|
@ -247,6 +253,8 @@ pub fn lower_crate(
|
|||
catch_scopes: Vec::new(),
|
||||
loop_scopes: Vec::new(),
|
||||
is_in_loop_condition: false,
|
||||
is_in_trait_impl: false,
|
||||
is_in_dyn_type: false,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
|
||||
type_def_lifetime_params: Default::default(),
|
||||
current_module: CRATE_NODE_ID,
|
||||
|
|
@ -256,7 +264,6 @@ pub fn lower_crate(
|
|||
is_generator: false,
|
||||
is_async_body: false,
|
||||
current_item: None,
|
||||
is_in_trait_impl: false,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_in_band_lifetimes: false,
|
||||
in_scope_lifetimes: Vec::new(),
|
||||
|
|
@ -670,14 +677,14 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
fn insert_item(&mut self, item: hir::Item) {
|
||||
let id = item.hir_id;
|
||||
// FIXME: Use debug_asset-rt
|
||||
// FIXME: Use `debug_asset-rt`.
|
||||
assert_eq!(id.local_id, hir::ItemLocalId::from_u32(0));
|
||||
self.items.insert(id, item);
|
||||
self.modules.get_mut(&self.current_module).unwrap().items.insert(id);
|
||||
}
|
||||
|
||||
fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
|
||||
// Setup the counter if needed
|
||||
// Set up the counter if needed.
|
||||
self.item_local_id_counters.entry(owner).or_insert(0);
|
||||
// Always allocate the first `HirId` for the owner itself.
|
||||
let lowered = self.lower_node_id_with_owner(owner, owner);
|
||||
|
|
@ -718,7 +725,7 @@ impl<'a> LoweringContext<'a> {
|
|||
{
|
||||
let counter = self.item_local_id_counters
|
||||
.insert(owner, HIR_ID_COUNTER_LOCKED)
|
||||
.unwrap_or_else(|| panic!("No item_local_id_counters entry for {:?}", owner));
|
||||
.unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
|
||||
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
|
||||
self.current_hir_id_owner.push((def_index, counter));
|
||||
let ret = f(self);
|
||||
|
|
@ -758,7 +765,7 @@ impl<'a> LoweringContext<'a> {
|
|||
let local_id_counter = this
|
||||
.item_local_id_counters
|
||||
.get_mut(&owner)
|
||||
.expect("called lower_node_id_with_owner before allocate_hir_id_counter");
|
||||
.expect("called `lower_node_id_with_owner` before `allocate_hir_id_counter`");
|
||||
let local_id = *local_id_counter;
|
||||
|
||||
// We want to be sure not to modify the counter in the map while it
|
||||
|
|
@ -771,7 +778,7 @@ impl<'a> LoweringContext<'a> {
|
|||
.resolver
|
||||
.definitions()
|
||||
.opt_def_index(owner)
|
||||
.expect("You forgot to call `create_def_with_parent` or are lowering node ids \
|
||||
.expect("you forgot to call `create_def_with_parent` or are lowering node-IDs \
|
||||
that do not belong to the current owner");
|
||||
|
||||
hir::HirId {
|
||||
|
|
@ -863,7 +870,7 @@ impl<'a> LoweringContext<'a> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Creates a new hir::GenericParam for every new lifetime and
|
||||
/// Creates a new `hir::GenericParam` for every new lifetime and
|
||||
/// type parameter encountered while evaluating `f`. Definitions
|
||||
/// are created with the parent provided. If no `parent_id` is
|
||||
/// provided, no definitions will be returned.
|
||||
|
|
@ -1197,7 +1204,7 @@ impl<'a> LoweringContext<'a> {
|
|||
assert_eq!(
|
||||
len + 1,
|
||||
self.loop_scopes.len(),
|
||||
"Loop scopes should be added and removed in stack order"
|
||||
"loop scopes should be added and removed in stack order"
|
||||
);
|
||||
|
||||
self.loop_scopes.pop().unwrap();
|
||||
|
|
@ -1221,6 +1228,20 @@ impl<'a> LoweringContext<'a> {
|
|||
result
|
||||
}
|
||||
|
||||
fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut LoweringContext<'_>) -> T,
|
||||
{
|
||||
let was_in_dyn_type = self.is_in_dyn_type;
|
||||
self.is_in_dyn_type = in_scope;
|
||||
|
||||
let result = f(self);
|
||||
|
||||
self.is_in_dyn_type = was_in_dyn_type;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn with_new_scopes<T, F>(&mut self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut LoweringContext<'_>) -> T,
|
||||
|
|
@ -1340,20 +1361,118 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_ty_binding(&mut self, b: &TypeBinding,
|
||||
itctx: ImplTraitContext<'_>) -> hir::TypeBinding {
|
||||
/// Given an associated type constraint like one of these:
|
||||
///
|
||||
/// ```
|
||||
/// T: Iterator<Item: Debug>
|
||||
/// ^^^^^^^^^^^
|
||||
/// T: Iterator<Item = Debug>
|
||||
/// ^^^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// returns a `hir::TypeBinding` representing `Item`.
|
||||
fn lower_assoc_ty_constraint(&mut self,
|
||||
c: &AssocTyConstraint,
|
||||
itctx: ImplTraitContext<'_>)
|
||||
-> hir::TypeBinding {
|
||||
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
|
||||
|
||||
let kind = match c.kind {
|
||||
AssocTyConstraintKind::Equality { ref ty } => hir::TypeBindingKind::Equality {
|
||||
ty: self.lower_ty(ty, itctx)
|
||||
},
|
||||
AssocTyConstraintKind::Bound { ref bounds } => {
|
||||
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
|
||||
let (desugar_to_impl_trait, itctx) = match itctx {
|
||||
// We are in the return position:
|
||||
//
|
||||
// fn foo() -> impl Iterator<Item: Debug>
|
||||
//
|
||||
// so desugar to
|
||||
//
|
||||
// fn foo() -> impl Iterator<Item = impl Debug>
|
||||
ImplTraitContext::Existential(_) => (true, itctx),
|
||||
|
||||
// We are in the argument position, but within a dyn type:
|
||||
//
|
||||
// fn foo(x: dyn Iterator<Item: Debug>)
|
||||
//
|
||||
// so desugar to
|
||||
//
|
||||
// fn foo(x: dyn Iterator<Item = impl Debug>)
|
||||
ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
|
||||
|
||||
// In `type Foo = dyn Iterator<Item: Debug>` we desugar to
|
||||
// `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
|
||||
// "impl trait context" to permit `impl Debug` in this position (it desugars
|
||||
// then to an existential type).
|
||||
//
|
||||
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
|
||||
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type =>
|
||||
(true, ImplTraitContext::Existential(None)),
|
||||
|
||||
// We are in the argument position, but not within a dyn type:
|
||||
//
|
||||
// fn foo(x: impl Iterator<Item: Debug>)
|
||||
//
|
||||
// so we leave it as is and this gets expanded in astconv to a bound like
|
||||
// `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
|
||||
// `impl Iterator`.
|
||||
_ => (false, itctx),
|
||||
};
|
||||
|
||||
if desugar_to_impl_trait {
|
||||
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
|
||||
// constructing the HIR for `impl bounds...` and then lowering that.
|
||||
|
||||
let impl_trait_node_id = self.sess.next_node_id();
|
||||
let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
|
||||
self.resolver.definitions().create_def_with_parent(
|
||||
parent_def_index,
|
||||
impl_trait_node_id,
|
||||
DefPathData::ImplTrait,
|
||||
Mark::root(),
|
||||
DUMMY_SP
|
||||
);
|
||||
|
||||
self.with_dyn_type_scope(false, |this| {
|
||||
let ty = this.lower_ty(
|
||||
&Ty {
|
||||
id: this.sess.next_node_id(),
|
||||
node: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
|
||||
span: DUMMY_SP,
|
||||
},
|
||||
itctx,
|
||||
);
|
||||
|
||||
hir::TypeBindingKind::Equality {
|
||||
ty
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Desugar `AssocTy: Bounds` into a type binding where the
|
||||
// later desugars into a trait predicate.
|
||||
let bounds = self.lower_param_bounds(bounds, itctx);
|
||||
|
||||
hir::TypeBindingKind::Constraint {
|
||||
bounds
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
hir::TypeBinding {
|
||||
hir_id: self.lower_node_id(b.id),
|
||||
ident: b.ident,
|
||||
ty: self.lower_ty(&b.ty, itctx),
|
||||
span: b.span,
|
||||
hir_id: self.lower_node_id(c.id),
|
||||
ident: c.ident,
|
||||
kind,
|
||||
span: c.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_generic_arg(&mut self,
|
||||
arg: &ast::GenericArg,
|
||||
itctx: ImplTraitContext<'_>)
|
||||
-> hir::GenericArg {
|
||||
arg: &ast::GenericArg,
|
||||
itctx: ImplTraitContext<'_>)
|
||||
-> hir::GenericArg {
|
||||
match arg {
|
||||
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)),
|
||||
ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)),
|
||||
|
|
@ -1445,23 +1564,26 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
TyKind::TraitObject(ref bounds, kind) => {
|
||||
let mut lifetime_bound = None;
|
||||
let bounds = bounds
|
||||
.iter()
|
||||
.filter_map(|bound| match *bound {
|
||||
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
|
||||
Some(self.lower_poly_trait_ref(ty, itctx.reborrow()))
|
||||
}
|
||||
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
|
||||
GenericBound::Outlives(ref lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
lifetime_bound = Some(self.lower_lifetime(lifetime));
|
||||
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
|
||||
let bounds = bounds
|
||||
.iter()
|
||||
.filter_map(|bound| match *bound {
|
||||
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
|
||||
Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
|
||||
}
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let lifetime_bound =
|
||||
lifetime_bound.unwrap_or_else(|| self.elided_dyn_bound(t.span));
|
||||
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
|
||||
GenericBound::Outlives(ref lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
lifetime_bound = Some(this.lower_lifetime(lifetime));
|
||||
}
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let lifetime_bound =
|
||||
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
|
||||
(bounds, lifetime_bound)
|
||||
});
|
||||
if kind != TraitObjectSyntax::Dyn {
|
||||
self.maybe_lint_bare_trait(t.span, t.id, false);
|
||||
}
|
||||
|
|
@ -1537,7 +1659,7 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
|
||||
TyKind::Mac(_) => bug!("`TyMac` should have been expanded by now."),
|
||||
TyKind::CVarArgs => {
|
||||
// Create the implicit lifetime of the "spoofed" `VaList`.
|
||||
let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
|
||||
|
|
@ -1563,10 +1685,10 @@ impl<'a> LoweringContext<'a> {
|
|||
// Make sure we know that some funky desugaring has been going on here.
|
||||
// This is a first: there is code in other places like for loop
|
||||
// desugaring that explicitly states that we don't want to track that.
|
||||
// Not tracking it makes lints in rustc and clippy very fragile as
|
||||
// Not tracking it makes lints in rustc and clippy very fragile, as
|
||||
// frequently opened issues show.
|
||||
let exist_ty_span = self.mark_span_with_reason(
|
||||
CompilerDesugaringKind::ExistentialReturnType,
|
||||
CompilerDesugaringKind::ExistentialType,
|
||||
span,
|
||||
None,
|
||||
);
|
||||
|
|
@ -1602,7 +1724,7 @@ impl<'a> LoweringContext<'a> {
|
|||
origin: hir::ExistTyOrigin::ReturnImplTrait,
|
||||
};
|
||||
|
||||
trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index);
|
||||
trace!("exist ty from impl trait def-index: {:#?}", exist_ty_def_index);
|
||||
let exist_ty_id = lctx.generate_existential_type(
|
||||
exist_ty_node_id,
|
||||
exist_ty_item,
|
||||
|
|
@ -1615,8 +1737,8 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Registers a new existential type with the proper NodeIds and
|
||||
/// returns the lowered node ID for the existential type.
|
||||
/// Registers a new existential type with the proper `NodeId`s and
|
||||
/// returns the lowered node-ID for the existential type.
|
||||
fn generate_existential_type(
|
||||
&mut self,
|
||||
exist_ty_node_id: NodeId,
|
||||
|
|
@ -1650,7 +1772,7 @@ impl<'a> LoweringContext<'a> {
|
|||
parent_index: DefIndex,
|
||||
bounds: &hir::GenericBounds,
|
||||
) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
|
||||
// This visitor walks over impl trait bounds and creates defs for all lifetimes which
|
||||
// This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
|
||||
// appear in the bounds, excluding lifetimes that are created within the bounds.
|
||||
// E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
|
||||
struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
|
||||
|
|
@ -1758,8 +1880,7 @@ impl<'a> LoweringContext<'a> {
|
|||
def_node_id,
|
||||
DefPathData::LifetimeNs(name.ident().as_interned_str()),
|
||||
Mark::root(),
|
||||
lifetime.span,
|
||||
);
|
||||
lifetime.span);
|
||||
|
||||
let (name, kind) = match name {
|
||||
hir::LifetimeName::Underscore => (
|
||||
|
|
@ -1770,7 +1891,7 @@ impl<'a> LoweringContext<'a> {
|
|||
param_name,
|
||||
hir::LifetimeParamKind::Explicit,
|
||||
),
|
||||
_ => bug!("expected LifetimeName::Param or ParamName::Plain"),
|
||||
_ => bug!("expected `LifetimeName::Param` or `ParamName::Plain`"),
|
||||
};
|
||||
|
||||
self.output_lifetime_params.push(hir::GenericParam {
|
||||
|
|
@ -1915,7 +2036,7 @@ impl<'a> LoweringContext<'a> {
|
|||
{
|
||||
ParenthesizedGenericArgs::Err
|
||||
}
|
||||
// A warning for now, for compatibility reasons
|
||||
// A warning for now, for compatibility reasons.
|
||||
_ => ParenthesizedGenericArgs::Warn,
|
||||
};
|
||||
|
||||
|
|
@ -2079,11 +2200,14 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
};
|
||||
err.emit();
|
||||
(self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
param_mode,
|
||||
itctx).0,
|
||||
false)
|
||||
(
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
param_mode,
|
||||
itctx
|
||||
).0,
|
||||
false,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -2109,11 +2233,11 @@ impl<'a> LoweringContext<'a> {
|
|||
let no_ty_args = generic_args.args.len() == expected_lifetimes;
|
||||
let no_bindings = generic_args.bindings.is_empty();
|
||||
let (incl_angl_brckt, insertion_span, suggestion) = if no_ty_args && no_bindings {
|
||||
// If there are no (non-implicit) generic args or associated-type
|
||||
// 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
|
||||
// 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 type args or bindings exist");
|
||||
|
|
@ -2191,24 +2315,28 @@ impl<'a> LoweringContext<'a> {
|
|||
param_mode: ParamMode,
|
||||
mut itctx: ImplTraitContext<'_>,
|
||||
) -> (hir::GenericArgs, bool) {
|
||||
let &AngleBracketedArgs { ref args, ref bindings, .. } = data;
|
||||
let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
|
||||
let has_types = args.iter().any(|arg| match arg {
|
||||
ast::GenericArg::Type(_) => true,
|
||||
_ => false,
|
||||
});
|
||||
(hir::GenericArgs {
|
||||
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
|
||||
bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx.reborrow())).collect(),
|
||||
parenthesized: false,
|
||||
},
|
||||
!has_types && param_mode == ParamMode::Optional)
|
||||
(
|
||||
hir::GenericArgs {
|
||||
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
|
||||
bindings: constraints.iter()
|
||||
.map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow()))
|
||||
.collect(),
|
||||
parenthesized: false,
|
||||
},
|
||||
!has_types && param_mode == ParamMode::Optional
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_parenthesized_parameter_data(
|
||||
&mut self,
|
||||
data: &ParenthesizedArgs,
|
||||
) -> (hir::GenericArgs, bool) {
|
||||
// Switch to `PassThrough` mode for anonymous lifetimes: this
|
||||
// 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
|
||||
|
|
@ -2231,10 +2359,17 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::TypeBinding {
|
||||
hir_id: this.next_id(),
|
||||
ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
|
||||
ty: output
|
||||
.as_ref()
|
||||
.map(|ty| this.lower_ty(&ty, ImplTraitContext::disallowed()))
|
||||
.unwrap_or_else(|| P(mk_tup(this, hir::HirVec::new(), span))),
|
||||
kind: hir::TypeBindingKind::Equality {
|
||||
ty: output
|
||||
.as_ref()
|
||||
.map(|ty| this.lower_ty(
|
||||
&ty,
|
||||
ImplTraitContext::disallowed()
|
||||
))
|
||||
.unwrap_or_else(||
|
||||
P(mk_tup(this, hir::HirVec::new(), span))
|
||||
),
|
||||
},
|
||||
span: output.as_ref().map_or(span, |ty| ty.span),
|
||||
}
|
||||
],
|
||||
|
|
@ -2300,16 +2435,16 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
// Lowers a function declaration.
|
||||
//
|
||||
// decl: the unlowered (ast) function declaration.
|
||||
// fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the
|
||||
// `decl`: the unlowered (AST) function declaration.
|
||||
// `fn_def_id`: if `Some`, impl Trait arguments are lowered into generic parameters on the
|
||||
// given DefId, otherwise impl Trait is disallowed. Must be `Some` if
|
||||
// make_ret_async is also `Some`.
|
||||
// impl_trait_return_allow: determines whether impl Trait can be used in return position.
|
||||
// This guards against trait declarations and implementations where impl Trait is
|
||||
// `make_ret_async` is also `Some`.
|
||||
// `impl_trait_return_allow`: determines whether `impl Trait` can be used in return position.
|
||||
// This guards against trait declarations and implementations where `impl Trait` is
|
||||
// disallowed.
|
||||
// make_ret_async: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
|
||||
// return type. This is used for `async fn` declarations. The `NodeId` is the id of the
|
||||
// return type impl Trait item.
|
||||
// `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
|
||||
// return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
|
||||
// return type `impl Trait` item.
|
||||
fn lower_fn_decl(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
|
|
@ -2350,7 +2485,7 @@ impl<'a> LoweringContext<'a> {
|
|||
);
|
||||
self.lower_async_fn_ret_ty(
|
||||
&decl.output,
|
||||
in_band_ty_params.expect("make_ret_async but no fn_def_id").0,
|
||||
in_band_ty_params.expect("`make_ret_async` but no `fn_def_id`").0,
|
||||
ret_id,
|
||||
lt_replacement,
|
||||
)
|
||||
|
|
@ -2359,7 +2494,8 @@ impl<'a> LoweringContext<'a> {
|
|||
FunctionRetTy::Ty(ref ty) => match in_band_ty_params {
|
||||
Some((def_id, _)) if impl_trait_return_allow => {
|
||||
hir::Return(self.lower_ty(ty,
|
||||
ImplTraitContext::Existential(Some(def_id))))
|
||||
ImplTraitContext::Existential(Some(def_id))
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed()))
|
||||
|
|
@ -2401,16 +2537,16 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
// Transform `-> T` for `async fn` into -> ExistTy { .. }
|
||||
// Transforms `-> T` for `async fn` into `-> ExistTy { .. }`
|
||||
// combined with the following definition of `ExistTy`:
|
||||
//
|
||||
// existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
|
||||
// existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
|
||||
//
|
||||
// inputs: lowered types of arguments to the function. Used to collect lifetimes.
|
||||
// output: unlowered output type (`T` in `-> T`)
|
||||
// fn_def_id: DefId of the parent function. Used to create child impl trait definition.
|
||||
// exist_ty_node_id: NodeId of the existential type that should be created.
|
||||
// elided_lt_replacement: replacement for elided lifetimes in the return type
|
||||
// `inputs`: lowered types of arguments to the function (used to collect lifetimes)
|
||||
// `output`: unlowered output type (`T` in `-> T`)
|
||||
// `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
|
||||
// `exist_ty_node_id`: `NodeId` of the existential type that should be created
|
||||
// `elided_lt_replacement`: replacement for elided lifetimes in the return type
|
||||
fn lower_async_fn_ret_ty(
|
||||
&mut self,
|
||||
output: &FunctionRetTy,
|
||||
|
|
@ -2511,7 +2647,7 @@ impl<'a> LoweringContext<'a> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Turns `-> T` into `Future<Output = T>`
|
||||
/// Transforms `-> T` into `Future<Output = T>`
|
||||
fn lower_async_fn_output_type_to_future_bound(
|
||||
&mut self,
|
||||
output: &FunctionRetTy,
|
||||
|
|
@ -2537,7 +2673,9 @@ impl<'a> LoweringContext<'a> {
|
|||
args: hir_vec![],
|
||||
bindings: hir_vec![hir::TypeBinding {
|
||||
ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
|
||||
ty: output_ty,
|
||||
kind: hir::TypeBindingKind::Equality {
|
||||
ty: output_ty,
|
||||
},
|
||||
hir_id: self.next_id(),
|
||||
span,
|
||||
}],
|
||||
|
|
@ -2722,7 +2860,7 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
let kind = hir::GenericParamKind::Type {
|
||||
default: default.as_ref().map(|x| {
|
||||
self.lower_ty(x, ImplTraitContext::disallowed())
|
||||
self.lower_ty(x, ImplTraitContext::Existential(None))
|
||||
}),
|
||||
synthetic: param.attrs.iter()
|
||||
.filter(|attr| attr.check_name(sym::rustc_synthetic))
|
||||
|
|
@ -2757,9 +2895,9 @@ impl<'a> LoweringContext<'a> {
|
|||
-> hir::Generics
|
||||
{
|
||||
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
|
||||
// FIXME: this could probably be done with less rightward drift. Also looks like two control
|
||||
// paths where report_error is called are also the only paths that advance to after
|
||||
// the match statement, so the error reporting could probably just be moved there.
|
||||
// FIXME: this could probably be done with less rightward drift. It also looks like two
|
||||
// control paths where `report_error` is called are the only paths that advance to after the
|
||||
// match statement, so the error reporting could probably just be moved there.
|
||||
let mut add_bounds: NodeMap<Vec<_>> = Default::default();
|
||||
for pred in &generics.where_clause.predicates {
|
||||
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
|
||||
|
|
@ -2952,7 +3090,7 @@ impl<'a> LoweringContext<'a> {
|
|||
hir_id: self.lower_node_id(f.id),
|
||||
ident: match f.ident {
|
||||
Some(ident) => ident,
|
||||
// FIXME(jseyfried): positional field hygiene
|
||||
// FIXME(jseyfried): positional field hygiene.
|
||||
None => Ident::new(sym::integer(index), f.span),
|
||||
},
|
||||
vis: self.lower_visibility(&f.vis, None),
|
||||
|
|
@ -2979,7 +3117,7 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn lower_param_bounds(&mut self, bounds: &[GenericBound], mut itctx: ImplTraitContext<'_>)
|
||||
-> hir::GenericBounds {
|
||||
-> hir::GenericBounds {
|
||||
bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
|
||||
}
|
||||
|
||||
|
|
@ -3157,7 +3295,7 @@ impl<'a> LoweringContext<'a> {
|
|||
match *i {
|
||||
ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(orig_name),
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
// Start with an empty prefix
|
||||
// Start with an empty prefix.
|
||||
let prefix = Path {
|
||||
segments: vec![],
|
||||
span: use_tree.span,
|
||||
|
|
@ -3230,22 +3368,28 @@ impl<'a> LoweringContext<'a> {
|
|||
self.lower_ty(t, ImplTraitContext::disallowed()),
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
),
|
||||
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy {
|
||||
generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
|
||||
impl_trait_fn: None,
|
||||
origin: hir::ExistTyOrigin::ExistentialType,
|
||||
}),
|
||||
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
|
||||
hir::EnumDef {
|
||||
variants: enum_definition
|
||||
.variants
|
||||
.iter()
|
||||
.map(|x| self.lower_variant(x))
|
||||
.collect(),
|
||||
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
|
||||
hir::ExistTy {
|
||||
generics: self.lower_generics(generics,
|
||||
ImplTraitContext::Existential(None)),
|
||||
bounds: self.lower_param_bounds(b,
|
||||
ImplTraitContext::Existential(None)),
|
||||
impl_trait_fn: None,
|
||||
origin: hir::ExistTyOrigin::ExistentialType,
|
||||
},
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
),
|
||||
ItemKind::Enum(ref enum_definition, ref generics) => {
|
||||
hir::ItemKind::Enum(
|
||||
hir::EnumDef {
|
||||
variants: enum_definition
|
||||
.variants
|
||||
.iter()
|
||||
.map(|x| self.lower_variant(x))
|
||||
.collect(),
|
||||
},
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
)
|
||||
},
|
||||
ItemKind::Struct(ref struct_def, ref generics) => {
|
||||
let struct_def = self.lower_variant_data(struct_def);
|
||||
hir::ItemKind::Struct(
|
||||
|
|
@ -3345,7 +3489,8 @@ impl<'a> LoweringContext<'a> {
|
|||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
|
||||
),
|
||||
ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
|
||||
ItemKind::MacroDef(..)
|
||||
| ItemKind::Mac(..) => bug!("`TyMac` should have been expanded by now"),
|
||||
}
|
||||
|
||||
// [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to
|
||||
|
|
@ -3623,16 +3768,18 @@ impl<'a> LoweringContext<'a> {
|
|||
);
|
||||
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
|
||||
}
|
||||
TraitItemKind::Type(ref bounds, ref default) => (
|
||||
self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
|
||||
hir::TraitItemKind::Type(
|
||||
TraitItemKind::Type(ref bounds, ref default) => {
|
||||
let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
|
||||
let node = hir::TraitItemKind::Type(
|
||||
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
|
||||
default
|
||||
.as_ref()
|
||||
.map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
|
||||
),
|
||||
),
|
||||
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
|
||||
);
|
||||
|
||||
(generics, node)
|
||||
},
|
||||
TraitItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
|
||||
};
|
||||
|
||||
hir::TraitItem {
|
||||
|
|
@ -3707,7 +3854,7 @@ impl<'a> LoweringContext<'a> {
|
|||
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
|
||||
),
|
||||
),
|
||||
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
|
||||
ImplItemKind::Macro(..) => bug!("`TyMac` should have been expanded by now"),
|
||||
};
|
||||
|
||||
hir::ImplItem {
|
||||
|
|
@ -5347,7 +5494,7 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
|
||||
/// Given a suffix `["b", "c", "d"]`, returns path `::std::b::c::d` when
|
||||
/// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
|
||||
/// The path is also resolved according to `is_value`.
|
||||
fn std_path(
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use std::iter::repeat;
|
|||
use crate::ich::StableHashingContext;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
|
||||
|
||||
/// A Visitor that walks over the HIR and collects Nodes into a HIR map
|
||||
/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
|
||||
pub(super) struct NodeCollector<'a, 'hir> {
|
||||
/// The crate
|
||||
krate: &'hir Crate,
|
||||
|
|
@ -45,7 +45,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
|
|||
|
||||
hcx: StableHashingContext<'a>,
|
||||
|
||||
// We are collecting DepNode::HirBody hashes here so we can compute the
|
||||
// We are collecting `DepNode::HirBody` hashes here so we can compute the
|
||||
// crate hash from then later on.
|
||||
hir_body_nodes: Vec<(DefPathHash, Fingerprint)>,
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
|||
|
||||
let mut hir_body_nodes = Vec::new();
|
||||
|
||||
// Allocate DepNodes for the root module
|
||||
// Allocate `DepNode`s for the root module.
|
||||
let (root_mod_sig_dep_index, root_mod_full_dep_index) = {
|
||||
let Crate {
|
||||
ref module,
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ impl DefPath {
|
|||
"{}[{}]",
|
||||
component.data.as_interned_str(),
|
||||
component.disambiguator)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +263,7 @@ impl DefPath {
|
|||
"{}[{}]",
|
||||
component.data.as_interned_str(),
|
||||
component.disambiguator)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
s
|
||||
|
|
@ -276,7 +276,7 @@ pub enum DefPathData {
|
|||
// they are treated specially by the `def_path` function.
|
||||
/// The crate root (marker)
|
||||
CrateRoot,
|
||||
// Catch-all for random DefId things like DUMMY_NODE_ID
|
||||
// Catch-all for random DefId things like `DUMMY_NODE_ID`
|
||||
Misc,
|
||||
// Different kinds of items and item-like things:
|
||||
/// An impl
|
||||
|
|
@ -298,9 +298,9 @@ pub enum DefPathData {
|
|||
AnonConst,
|
||||
/// An `impl Trait` type node
|
||||
ImplTrait,
|
||||
/// GlobalMetaData identifies a piece of crate metadata that is global to
|
||||
/// a whole crate (as opposed to just one item). GlobalMetaData components
|
||||
/// are only supposed to show up right below the crate root.
|
||||
/// Identifies a piece of crate metadata that is global to a whole crate
|
||||
/// (as opposed to just one item). `GlobalMetaData` components are only
|
||||
/// supposed to show up right below the crate root.
|
||||
GlobalMetaData(InternedString),
|
||||
}
|
||||
|
||||
|
|
@ -397,6 +397,11 @@ impl Definitions {
|
|||
self.node_to_hir_id[node_id]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn def_index_to_node_id(&self, def_index: DefIndex) -> ast::NodeId {
|
||||
self.as_local_node_id(DefId::local(def_index)).unwrap()
|
||||
}
|
||||
|
||||
/// Retrieves the span of the given `DefId` if `DefId` is in the local crate, the span exists
|
||||
/// and it's not `DUMMY_SP`.
|
||||
#[inline]
|
||||
|
|
@ -442,7 +447,7 @@ impl Definitions {
|
|||
root_index
|
||||
}
|
||||
|
||||
/// Add a definition with a parent definition.
|
||||
/// Adds a definition with a parent definition.
|
||||
pub fn create_def_with_parent(&mut self,
|
||||
parent: DefIndex,
|
||||
node_id: ast::NodeId,
|
||||
|
|
@ -559,7 +564,7 @@ impl DefPathData {
|
|||
GlobalMetaData(name) => {
|
||||
return name
|
||||
}
|
||||
// note that this does not show up in user printouts
|
||||
// Note that this does not show up in user print-outs.
|
||||
CrateRoot => sym::double_braced_crate,
|
||||
Impl => sym::double_braced_impl,
|
||||
Misc => sym::double_braced_misc,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use self::collector::NodeCollector;
|
||||
pub use self::def_collector::{DefCollector, MacroInvocationData};
|
||||
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
|
||||
DisambiguatedDefPathData, DefPathHash};
|
||||
pub use self::definitions::{
|
||||
Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData, DefPathHash
|
||||
};
|
||||
|
||||
use crate::dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex};
|
||||
|
||||
|
|
@ -238,7 +239,7 @@ impl<'hir> Map<'hir> {
|
|||
})
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
#[inline]
|
||||
pub fn local_def_id_from_hir_id(&self, hir_id: HirId) -> DefId {
|
||||
self.opt_local_def_id_from_hir_id(hir_id).unwrap_or_else(|| {
|
||||
|
|
@ -247,7 +248,7 @@ impl<'hir> Map<'hir> {
|
|||
})
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
#[inline]
|
||||
pub fn opt_local_def_id_from_hir_id(&self, hir_id: HirId) -> Option<DefId> {
|
||||
let node_id = self.hir_to_node_id(hir_id);
|
||||
|
|
@ -264,7 +265,7 @@ impl<'hir> Map<'hir> {
|
|||
self.definitions.as_local_node_id(def_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
#[inline]
|
||||
pub fn as_local_hir_id(&self, def_id: DefId) -> Option<HirId> {
|
||||
self.definitions.as_local_hir_id(def_id)
|
||||
|
|
@ -287,7 +288,7 @@ impl<'hir> Map<'hir> {
|
|||
|
||||
#[inline]
|
||||
pub fn def_index_to_node_id(&self, def_index: DefIndex) -> NodeId {
|
||||
self.definitions.as_local_node_id(DefId::local(def_index)).unwrap()
|
||||
self.definitions.def_index_to_node_id(def_index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -426,7 +427,7 @@ impl<'hir> Map<'hir> {
|
|||
self.fn_decl_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<FnDecl> {
|
||||
if let Some(entry) = self.find_entry(hir_id) {
|
||||
entry.fn_decl().cloned()
|
||||
|
|
@ -455,7 +456,7 @@ impl<'hir> Map<'hir> {
|
|||
self.maybe_body_owned_by_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn maybe_body_owned_by_by_hir_id(&self, hir_id: HirId) -> Option<BodyId> {
|
||||
if let Some(entry) = self.find_entry(hir_id) {
|
||||
if self.dep_graph.is_fully_enabled() {
|
||||
|
|
@ -483,7 +484,7 @@ impl<'hir> Map<'hir> {
|
|||
self.body_owner_kind_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn body_owner_kind_by_hir_id(&self, id: HirId) -> BodyOwnerKind {
|
||||
match self.get_by_hir_id(id) {
|
||||
Node::Item(&Item { node: ItemKind::Const(..), .. }) |
|
||||
|
|
@ -587,14 +588,13 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Retrieve the Node corresponding to `id`, panicking if it cannot
|
||||
/// be found.
|
||||
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
|
||||
pub fn get(&self, id: NodeId) -> Node<'hir> {
|
||||
let hir_id = self.node_to_hir_id(id);
|
||||
self.get_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn get_by_hir_id(&self, id: HirId) -> Node<'hir> {
|
||||
// read recorded by `find`
|
||||
self.find_by_hir_id(id).unwrap_or_else(||
|
||||
|
|
@ -634,7 +634,7 @@ impl<'hir> Map<'hir> {
|
|||
self.find_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn find_by_hir_id(&self, hir_id: HirId) -> Option<Node<'hir>> {
|
||||
let result = self.find_entry(hir_id).and_then(|entry| {
|
||||
if let Node::Crate = entry.node {
|
||||
|
|
@ -649,23 +649,23 @@ impl<'hir> Map<'hir> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Similar to `get_parent`; returns the parent node-id, or own `id` if there is
|
||||
/// no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself
|
||||
/// present in the map -- so passing the return value of get_parent_node to
|
||||
/// get may actually panic.
|
||||
/// This function returns the immediate parent in the AST, whereas get_parent
|
||||
/// Similar to `get_parent`; returns the parent node-ID, or just `hir_id` if there
|
||||
/// is no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself
|
||||
/// present in the map, so passing the return value of `get_parent_node` to
|
||||
/// `get` may in fact panic.
|
||||
/// This function returns the immediate parent in the AST, whereas `get_parent`
|
||||
/// returns the enclosing item. Note that this might not be the actual parent
|
||||
/// node in the AST - some kinds of nodes are not in the map and these will
|
||||
/// never appear as the parent_node. So you can always walk the `parent_nodes`
|
||||
/// from a node to the root of the ast (unless you get the same ID back here
|
||||
/// that can happen if the ID is not in the map itself or is just weird).
|
||||
/// node in the AST -- some kinds of nodes are not in the map and these will
|
||||
/// never appear as the parent node. Thus, you can always walk the parent nodes
|
||||
/// from a node to the root of the AST (unless you get back the same ID here,
|
||||
/// which can happen if the ID is not in the map itself or is just weird).
|
||||
pub fn get_parent_node(&self, id: NodeId) -> NodeId {
|
||||
let hir_id = self.node_to_hir_id(id);
|
||||
let parent_hir_id = self.get_parent_node_by_hir_id(hir_id);
|
||||
self.hir_to_node_id(parent_hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn get_parent_node_by_hir_id(&self, hir_id: HirId) -> HirId {
|
||||
if self.dep_graph.is_fully_enabled() {
|
||||
let hir_id_owner = hir_id.owner;
|
||||
|
|
@ -721,24 +721,24 @@ impl<'hir> Map<'hir> {
|
|||
{
|
||||
let mut id = start_id;
|
||||
loop {
|
||||
let parent_node = self.get_parent_node_by_hir_id(id);
|
||||
if parent_node == CRATE_HIR_ID {
|
||||
let parent_id = self.get_parent_node_by_hir_id(id);
|
||||
if parent_id == CRATE_HIR_ID {
|
||||
return Ok(CRATE_HIR_ID);
|
||||
}
|
||||
if parent_node == id {
|
||||
if parent_id == id {
|
||||
return Err(id);
|
||||
}
|
||||
|
||||
if let Some(entry) = self.find_entry(parent_node) {
|
||||
if let Some(entry) = self.find_entry(parent_id) {
|
||||
if let Node::Crate = entry.node {
|
||||
return Err(id);
|
||||
}
|
||||
if found(&entry.node) {
|
||||
return Ok(parent_node);
|
||||
return Ok(parent_id);
|
||||
} else if bail_early(&entry.node) {
|
||||
return Err(parent_node);
|
||||
return Err(parent_id);
|
||||
}
|
||||
id = parent_node;
|
||||
id = parent_id;
|
||||
} else {
|
||||
return Err(id);
|
||||
}
|
||||
|
|
@ -803,7 +803,7 @@ impl<'hir> Map<'hir> {
|
|||
self.hir_to_node_id(parent_hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
|
||||
match self.walk_parent_nodes(hir_id, |node| match *node {
|
||||
Node::Item(_) |
|
||||
|
|
@ -824,7 +824,7 @@ impl<'hir> Map<'hir> {
|
|||
self.get_module_parent_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn get_module_parent_by_hir_id(&self, id: HirId) -> DefId {
|
||||
self.local_def_id_from_hir_id(self.get_module_parent_node(id))
|
||||
}
|
||||
|
|
@ -841,27 +841,72 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the nearest enclosing scope. A scope is an item or block.
|
||||
/// FIXME: it is not clear to me that all items qualify as scopes -- statics
|
||||
/// and associated types probably shouldn't, for example. Behavior in this
|
||||
/// regard should be expected to be highly unstable.
|
||||
/// Returns the nearest enclosing scope. A scope is roughly an item or block.
|
||||
pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
|
||||
self.walk_parent_nodes(hir_id, |node| match *node {
|
||||
Node::Item(_) |
|
||||
Node::ForeignItem(_) |
|
||||
Node::TraitItem(_) |
|
||||
Node::ImplItem(_) |
|
||||
Node::Item(i) => {
|
||||
match i.node {
|
||||
ItemKind::Fn(..)
|
||||
| ItemKind::Mod(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::Union(..)
|
||||
| ItemKind::Trait(..)
|
||||
| ItemKind::Impl(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
Node::ForeignItem(fi) => {
|
||||
match fi.node {
|
||||
ForeignItemKind::Fn(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
Node::TraitItem(ti) => {
|
||||
match ti.node {
|
||||
TraitItemKind::Method(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
Node::ImplItem(ii) => {
|
||||
match ii.node {
|
||||
ImplItemKind::Method(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
Node::Block(_) => true,
|
||||
_ => false,
|
||||
}, |_| false).ok()
|
||||
}
|
||||
|
||||
/// Returns the defining scope for an existential type definition.
|
||||
pub fn get_defining_scope(&self, id: HirId) -> Option<HirId> {
|
||||
let mut scope = id;
|
||||
loop {
|
||||
scope = self.get_enclosing_scope(scope)?;
|
||||
if scope == CRATE_HIR_ID {
|
||||
return Some(CRATE_HIR_ID);
|
||||
}
|
||||
match self.get_by_hir_id(scope) {
|
||||
Node::Item(i) => {
|
||||
match i.node {
|
||||
ItemKind::Existential(ExistTy { impl_trait_fn: None, .. }) => {}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
Node::Block(_) => {}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
Some(scope)
|
||||
}
|
||||
|
||||
pub fn get_parent_did(&self, id: NodeId) -> DefId {
|
||||
let hir_id = self.node_to_hir_id(id);
|
||||
self.get_parent_did_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn get_parent_did_by_hir_id(&self, id: HirId) -> DefId {
|
||||
self.local_def_id_from_hir_id(self.get_parent_item(id))
|
||||
}
|
||||
|
|
@ -871,7 +916,7 @@ impl<'hir> Map<'hir> {
|
|||
self.get_foreign_abi_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn get_foreign_abi_by_hir_id(&self, hir_id: HirId) -> Abi {
|
||||
let parent = self.get_parent_item(hir_id);
|
||||
if let Some(entry) = self.find_entry(parent) {
|
||||
|
|
@ -890,7 +935,7 @@ impl<'hir> Map<'hir> {
|
|||
self.expect_item_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn expect_item_by_hir_id(&self, id: HirId) -> &'hir Item {
|
||||
match self.find_by_hir_id(id) { // read recorded by `find`
|
||||
Some(Node::Item(item)) => item,
|
||||
|
|
@ -946,7 +991,7 @@ impl<'hir> Map<'hir> {
|
|||
self.expect_expr_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn expect_expr_by_hir_id(&self, id: HirId) -> &'hir Expr {
|
||||
match self.find_by_hir_id(id) { // read recorded by find
|
||||
Some(Node::Expr(expr)) => expr,
|
||||
|
|
@ -960,7 +1005,7 @@ impl<'hir> Map<'hir> {
|
|||
self.name_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn name_by_hir_id(&self, id: HirId) -> Name {
|
||||
match self.get_by_hir_id(id) {
|
||||
Node::Item(i) => i.ident.name,
|
||||
|
|
@ -977,14 +1022,14 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given a node ID, get a list of attributes associated with the AST
|
||||
/// corresponding to the Node ID
|
||||
/// Given a node ID, gets a list of attributes associated with the AST
|
||||
/// corresponding to the node-ID.
|
||||
pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] {
|
||||
let hir_id = self.node_to_hir_id(id);
|
||||
self.attrs_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn attrs_by_hir_id(&self, id: HirId) -> &'hir [ast::Attribute] {
|
||||
self.read(id); // reveals attributes on the node
|
||||
let attrs = match self.find_entry(id).map(|entry| entry.node) {
|
||||
|
|
@ -1053,7 +1098,7 @@ impl<'hir> Map<'hir> {
|
|||
self.span_by_hir_id(hir_id)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn span_by_hir_id(&self, hir_id: HirId) -> Span {
|
||||
self.read(hir_id); // reveals span from node
|
||||
match self.find_entry(hir_id).map(|entry| entry.node) {
|
||||
|
|
@ -1101,7 +1146,7 @@ impl<'hir> Map<'hir> {
|
|||
hir_id_to_string(self, self.node_to_hir_id(id), true)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn hir_to_string(&self, id: HirId) -> String {
|
||||
hir_id_to_string(self, id, true)
|
||||
}
|
||||
|
|
@ -1110,7 +1155,7 @@ impl<'hir> Map<'hir> {
|
|||
hir_id_to_string(self, self.node_to_hir_id(id), false)
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn hir_to_user_string(&self, id: HirId) -> String {
|
||||
hir_id_to_string(self, id, false)
|
||||
}
|
||||
|
|
@ -1119,7 +1164,7 @@ impl<'hir> Map<'hir> {
|
|||
print::to_string(self, |s| s.print_node(self.get(id)))
|
||||
}
|
||||
|
||||
// FIXME(@ljedrz): replace the NodeId variant
|
||||
// FIXME(@ljedrz): replace the `NodeId` variant.
|
||||
pub fn hir_to_pretty_string(&self, id: HirId) -> String {
|
||||
print::to_string(self, |s| s.print_node(self.get_by_hir_id(id)))
|
||||
}
|
||||
|
|
@ -1451,8 +1496,9 @@ pub fn provide(providers: &mut Providers<'_>) {
|
|||
if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
|
||||
tcx.hir().def_kind(node_id)
|
||||
} else {
|
||||
bug!("Calling local def_kind query provider for upstream DefId: {:?}",
|
||||
def_id)
|
||||
bug!("calling local def_kind query provider for upstream DefId: {:?}",
|
||||
def_id
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// HIR datatypes. See the [rustc guide] for more info.
|
||||
//! HIR datatypes. See the [rustc guide] for more info.
|
||||
//!
|
||||
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/hir.html
|
||||
|
||||
|
|
@ -121,13 +121,13 @@ impl fmt::Display for HirId {
|
|||
}
|
||||
}
|
||||
|
||||
// hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
|
||||
// Hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
|
||||
mod item_local_id_inner {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_macros::HashStable;
|
||||
newtype_index! {
|
||||
/// An `ItemLocalId` uniquely identifies something within a given "item-like",
|
||||
/// that is, within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
|
||||
/// An `ItemLocalId` uniquely identifies something within a given "item-like";
|
||||
/// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
|
||||
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
|
||||
/// the node's position within the owning item in any way, but there is a
|
||||
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
|
||||
|
|
@ -568,7 +568,6 @@ pub struct GenericParam {
|
|||
pub bounds: GenericBounds,
|
||||
pub span: Span,
|
||||
pub pure_wrt_drop: bool,
|
||||
|
||||
pub kind: GenericParamKind,
|
||||
}
|
||||
|
||||
|
|
@ -1566,13 +1565,13 @@ pub enum ExprKind {
|
|||
|
||||
/// A struct or struct-like variant literal expression.
|
||||
///
|
||||
/// For example, `Foo {x: 1, y: 2}`, or
|
||||
/// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
|
||||
/// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`,
|
||||
/// where `base` is the `Option<Expr>`.
|
||||
Struct(P<QPath>, HirVec<Field>, Option<P<Expr>>),
|
||||
|
||||
/// An array literal constructed from one repeated element.
|
||||
///
|
||||
/// For example, `[1; 5]`. The first expression is the element
|
||||
/// E.g., `[1; 5]`. The first expression is the element
|
||||
/// to be repeated; the second is the number of times to repeat it.
|
||||
Repeat(P<Expr>, AnonConst),
|
||||
|
||||
|
|
@ -1583,7 +1582,7 @@ pub enum ExprKind {
|
|||
Err,
|
||||
}
|
||||
|
||||
/// Optionally `Self`-qualified value/type path or associated extension.
|
||||
/// Represents an optionally `Self`-qualified value/type path or associated extension.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum QPath {
|
||||
/// Path to a definition, optionally "fully-qualified" with a `Self`
|
||||
|
|
@ -1738,7 +1737,7 @@ pub struct TraitItem {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
/// A trait method's body (or just argument names).
|
||||
/// Represents a trait method's body (or just argument names).
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum TraitMethod {
|
||||
/// No default body in the trait, just a signature.
|
||||
|
|
@ -1751,13 +1750,12 @@ pub enum TraitMethod {
|
|||
/// Represents a trait method or associated constant or type
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum TraitItemKind {
|
||||
/// An associated constant with an optional value (otherwise `impl`s
|
||||
/// must contain a value)
|
||||
/// An associated constant with an optional value (otherwise `impl`s must contain a value).
|
||||
Const(P<Ty>, Option<BodyId>),
|
||||
/// A method with an optional body
|
||||
/// A method with an optional body.
|
||||
Method(MethodSig, TraitMethod),
|
||||
/// An associated type with (possibly empty) bounds and optional concrete
|
||||
/// type
|
||||
/// type.
|
||||
Type(GenericBounds, Option<P<Ty>>),
|
||||
}
|
||||
|
||||
|
|
@ -1782,7 +1780,7 @@ pub struct ImplItem {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
/// Represents different contents within `impl`s
|
||||
/// Represents various kinds of content within an `impl`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum ImplItemKind {
|
||||
/// An associated constant of the given type, set to the constant result
|
||||
|
|
@ -1796,21 +1794,56 @@ pub enum ImplItemKind {
|
|||
Existential(GenericBounds),
|
||||
}
|
||||
|
||||
// Bind a type to an associated type: `A=Foo`.
|
||||
/// Bind a type to an associated type (i.e., `A = Foo`).
|
||||
///
|
||||
/// Bindings like `A: Debug` are represented as a special type `A =
|
||||
/// $::Debug` that is understood by the astconv code.
|
||||
///
|
||||
/// FIXME(alexreg) -- why have a separate type for the binding case,
|
||||
/// wouldn't it be better to make the `ty` field an enum like:
|
||||
///
|
||||
/// ```
|
||||
/// enum TypeBindingKind {
|
||||
/// Equals(...),
|
||||
/// Binding(...),
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct TypeBinding {
|
||||
pub hir_id: HirId,
|
||||
#[stable_hasher(project(name))]
|
||||
pub ident: Ident,
|
||||
pub ty: P<Ty>,
|
||||
pub kind: TypeBindingKind,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// Represents the two kinds of type bindings.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum TypeBindingKind {
|
||||
/// E.g., `Foo<Bar: Send>`.
|
||||
Constraint {
|
||||
bounds: HirVec<GenericBound>,
|
||||
},
|
||||
/// E.g., `Foo<Bar = ()>`.
|
||||
Equality {
|
||||
ty: P<Ty>,
|
||||
},
|
||||
}
|
||||
|
||||
impl TypeBinding {
|
||||
pub fn ty(&self) -> &Ty {
|
||||
match self.kind {
|
||||
TypeBindingKind::Equality { ref ty } => ty,
|
||||
_ => bug!("expected equality type binding for parenthesized generic args"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct Ty {
|
||||
pub hir_id: HirId,
|
||||
pub node: TyKind,
|
||||
pub span: Span,
|
||||
pub hir_id: HirId,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Ty {
|
||||
|
|
@ -1874,7 +1907,7 @@ pub enum TyKind {
|
|||
BareFn(P<BareFnTy>),
|
||||
/// The never type (`!`).
|
||||
Never,
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
/// A tuple (`(A, B, C, D, ...)`).
|
||||
Tup(HirVec<Ty>),
|
||||
/// A path to a type definition (`module::module::...::Type`), or an
|
||||
/// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
|
||||
|
|
@ -2236,18 +2269,18 @@ impl StructField {
|
|||
}
|
||||
}
|
||||
|
||||
/// Fields and constructor ids of enum variants and structs
|
||||
/// Fields and constructor IDs of enum variants and structs.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub enum VariantData {
|
||||
/// Struct variant.
|
||||
/// A struct variant.
|
||||
///
|
||||
/// e.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
|
||||
/// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
|
||||
Struct(HirVec<StructField>, /* recovered */ bool),
|
||||
/// Tuple variant.
|
||||
/// A tuple variant.
|
||||
///
|
||||
/// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
|
||||
Tuple(HirVec<StructField>, HirId),
|
||||
/// Unit variant.
|
||||
/// A unit variant.
|
||||
///
|
||||
/// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`.
|
||||
Unit(HirId),
|
||||
|
|
@ -2598,7 +2631,7 @@ impl CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
/// True if it looks like this symbol needs to be exported, for example:
|
||||
/// Returns `true` if it looks like this symbol needs to be exported, for example:
|
||||
///
|
||||
/// * `#[no_mangle]` is present
|
||||
/// * `#[export_name(...)]` is present
|
||||
|
|
@ -2607,8 +2640,8 @@ impl CodegenFnAttrs {
|
|||
self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) ||
|
||||
self.export_name.is_some() ||
|
||||
match self.linkage {
|
||||
// these are private, make sure we don't try to consider
|
||||
// them external
|
||||
// These are private, so make sure we don't try to consider
|
||||
// them external.
|
||||
None |
|
||||
Some(Linkage::Internal) |
|
||||
Some(Linkage::Private) => false,
|
||||
|
|
|
|||
|
|
@ -1645,7 +1645,7 @@ impl<'a> State<'a> {
|
|||
|
||||
self.space_if_not_bol()?;
|
||||
self.word_space("->")?;
|
||||
self.print_type(&generic_args.bindings[0].ty)?;
|
||||
self.print_type(generic_args.bindings[0].ty())?;
|
||||
} else {
|
||||
let start = if colons_before_params { "::<" } else { "<" };
|
||||
let empty = Cell::new(true);
|
||||
|
|
@ -1679,8 +1679,8 @@ impl<'a> State<'a> {
|
|||
})?;
|
||||
}
|
||||
|
||||
// FIXME(eddyb) This would leak into error messages, e.g.:
|
||||
// "non-exhaustive patterns: `Some::<..>(_)` not covered".
|
||||
// FIXME(eddyb): this would leak into error messages (e.g.,
|
||||
// "non-exhaustive patterns: `Some::<..>(_)` not covered").
|
||||
if infer_types && false {
|
||||
start_or_comma(self)?;
|
||||
self.s.word("..")?;
|
||||
|
|
@ -1690,8 +1690,15 @@ impl<'a> State<'a> {
|
|||
start_or_comma(self)?;
|
||||
self.print_ident(binding.ident)?;
|
||||
self.s.space()?;
|
||||
self.word_space("=")?;
|
||||
self.print_type(&binding.ty)?;
|
||||
match generic_args.bindings[0].kind {
|
||||
hir::TypeBindingKind::Equality { ref ty } => {
|
||||
self.word_space("=")?;
|
||||
self.print_type(ty)?;
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { ref bounds } => {
|
||||
self.print_bounds(":", bounds)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !empty.get() {
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
|
|||
|
||||
inner_span.hash_stable(hcx, hasher);
|
||||
|
||||
// Combining the DefPathHashes directly is faster than feeding them
|
||||
// Combining the `DefPathHash`s directly is faster than feeding them
|
||||
// into the hasher. Because we use a commutative combine, we also don't
|
||||
// have to sort the array.
|
||||
let item_ids_hash = item_ids
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
|
|||
Async,
|
||||
Await,
|
||||
QuestionMark,
|
||||
ExistentialReturnType,
|
||||
ExistentialType,
|
||||
ForLoop,
|
||||
TryBlock
|
||||
});
|
||||
|
|
|
|||
|
|
@ -914,10 +914,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// variable, and because type variable's can't (at present, at
|
||||
// least) capture any of the things bound by this binder.
|
||||
//
|
||||
// Really, there is no *particular* reason to do this
|
||||
// `shallow_resolve` here except as a
|
||||
// micro-optimization. Naturally I could not
|
||||
// resist. -nmatsakis
|
||||
// NOTE(nmatsakis): really, there is no *particular* reason to do this
|
||||
// `shallow_resolve` here except as a micro-optimization.
|
||||
// Naturally I could not resist.
|
||||
let two_unbound_type_vars = {
|
||||
let a = self.shallow_resolve(predicate.skip_binder().a);
|
||||
let b = self.shallow_resolve(predicate.skip_binder().b);
|
||||
|
|
|
|||
|
|
@ -786,13 +786,13 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
match tcx.hir().find_by_hir_id(opaque_hir_id)
|
||||
{
|
||||
Some(Node::Item(item)) => match item.node {
|
||||
// impl trait
|
||||
// Anonymous `impl Trait`
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: Some(parent),
|
||||
origin,
|
||||
..
|
||||
}) => (parent == self.parent_def_id, origin),
|
||||
// named existential types
|
||||
// Named `existential type`
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: None,
|
||||
origin,
|
||||
|
|
@ -858,7 +858,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
def_id, substs
|
||||
);
|
||||
|
||||
// Use the same type variable if the exact same Opaque appears more
|
||||
// Use the same type variable if the exact same opaque type appears more
|
||||
// than once in the return type (e.g., if it's passed to a type alias).
|
||||
if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
|
||||
return opaque_defn.concrete_ty;
|
||||
|
|
@ -871,7 +871,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
debug!(
|
||||
"instantiate_opaque_types: predicates: {:#?}",
|
||||
"instantiate_opaque_types: predicates={:#?}",
|
||||
predicates_of,
|
||||
);
|
||||
let bounds = predicates_of.instantiate(tcx, substs);
|
||||
|
|
@ -883,15 +883,15 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
required_region_bounds
|
||||
);
|
||||
|
||||
// make sure that we are in fact defining the *entire* type
|
||||
// e.g., `existential type Foo<T: Bound>: Bar;` needs to be
|
||||
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`.
|
||||
// Make sure that we are in fact defining the *entire* type
|
||||
// (e.g., `existential type Foo<T: Bound>: Bar;` needs to be
|
||||
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
|
||||
debug!(
|
||||
"instantiate_opaque_types: param_env: {:#?}",
|
||||
"instantiate_opaque_types: param_env={:#?}",
|
||||
self.param_env,
|
||||
);
|
||||
debug!(
|
||||
"instantiate_opaque_types: generics: {:#?}",
|
||||
"instantiate_opaque_types: generics={:#?}",
|
||||
tcx.generics_of(def_id),
|
||||
);
|
||||
|
||||
|
|
@ -925,8 +925,9 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `opaque_node_id` is a sibling or a child of a sibling of `def_id`.
|
||||
/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
/// pub mod foo {
|
||||
/// pub mod bar {
|
||||
|
|
@ -939,27 +940,29 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here, `def_id` is the `DefId` of the existential type `Baz` and `opaque_node_id` is the
|
||||
/// `NodeId` of the reference to `Baz` (i.e., the return type of both `f1` and `f2`).
|
||||
/// We return `true` if the reference is within the same module as the existential type
|
||||
/// (i.e., `true` for `f1`, `false` for `f2`).
|
||||
/// Here, `def_id` is the `DefId` of the defining use of the existential type (e.g., `f1` or `f2`),
|
||||
/// and `opaque_hir_id` is the `HirId` of the definition of the existential type `Baz`.
|
||||
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
|
||||
pub fn may_define_existential_type(
|
||||
tcx: TyCtxt<'_, '_, '_>,
|
||||
def_id: DefId,
|
||||
opaque_hir_id: hir::HirId,
|
||||
) -> bool {
|
||||
let mut hir_id = tcx
|
||||
.hir()
|
||||
.as_local_hir_id(def_id)
|
||||
.unwrap();
|
||||
// named existential types can be defined by any siblings or
|
||||
// children of siblings
|
||||
let mod_id = tcx.hir().get_parent_item(opaque_hir_id);
|
||||
// so we walk up the node tree until we hit the root or the parent
|
||||
// of the opaque type
|
||||
while hir_id != mod_id && hir_id != hir::CRATE_HIR_ID {
|
||||
let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
trace!(
|
||||
"may_define_existential_type(def={:?}, opaque_node={:?})",
|
||||
tcx.hir().get_by_hir_id(hir_id),
|
||||
tcx.hir().get_by_hir_id(opaque_hir_id)
|
||||
);
|
||||
|
||||
// Named existential types can be defined by any siblings or children of siblings.
|
||||
let scope = tcx.hir()
|
||||
.get_defining_scope(opaque_hir_id)
|
||||
.expect("could not get defining scope");
|
||||
// We walk up the node tree until we hit the root or the scope of the opaque type.
|
||||
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
|
||||
hir_id = tcx.hir().get_parent_item(hir_id);
|
||||
}
|
||||
// syntactically we are allowed to define the concrete type
|
||||
hir_id == mod_id
|
||||
// Syntactically, we are allowed to define the concrete type if:
|
||||
hir_id == scope
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Name resolution for lifetimes.
|
||||
//!
|
||||
//! Name resolution for lifetimes follows MUCH simpler rules than the
|
||||
//! Name resolution for lifetimes follows *much* simpler rules than the
|
||||
//! full resolve. For example, lifetime names are never exported or
|
||||
//! used between functions, and they operate in a purely top-down
|
||||
//! way. Therefore, we break lifetime name resolution into a separate pass.
|
||||
|
|
@ -923,7 +923,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl) {
|
||||
let output = match fd.output {
|
||||
hir::DefaultReturn(_) => None,
|
||||
hir::Return(ref ty) => Some(ty),
|
||||
hir::Return(ref ty) => Some(&**ty),
|
||||
};
|
||||
self.visit_fn_like_elision(&fd.inputs, output);
|
||||
}
|
||||
|
|
@ -1009,7 +1009,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
trait_ref: &'tcx hir::PolyTraitRef,
|
||||
_modifier: hir::TraitBoundModifier,
|
||||
) {
|
||||
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
|
||||
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
|
||||
|
||||
if !self.trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| {
|
||||
match param.kind {
|
||||
|
|
@ -1884,7 +1884,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
if generic_args.parenthesized {
|
||||
let was_in_fn_syntax = self.is_in_fn_syntax;
|
||||
self.is_in_fn_syntax = true;
|
||||
self.visit_fn_like_elision(generic_args.inputs(), Some(&generic_args.bindings[0].ty));
|
||||
self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty()));
|
||||
self.is_in_fn_syntax = was_in_fn_syntax;
|
||||
return;
|
||||
}
|
||||
|
|
@ -2020,7 +2020,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_fn_like_elision(&mut self, inputs: &'tcx [hir::Ty], output: Option<&'tcx P<hir::Ty>>) {
|
||||
fn visit_fn_like_elision(&mut self, inputs: &'tcx [hir::Ty], output: Option<&'tcx hir::Ty>) {
|
||||
debug!("visit_fn_like_elision: enter");
|
||||
let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
|
||||
let arg_scope = Scope::Elision {
|
||||
|
|
|
|||
|
|
@ -124,12 +124,12 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
|
|||
// This crate explicitly wants staged API.
|
||||
debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
|
||||
if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
|
||||
self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged api, \
|
||||
self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged API; \
|
||||
use `#[rustc_deprecated]` instead");
|
||||
}
|
||||
if let Some(mut stab) = attr::find_stability(&self.tcx.sess.parse_sess,
|
||||
attrs, item_sp) {
|
||||
// Error if prohibited, or can't inherit anything from a container
|
||||
// Error if prohibited, or can't inherit anything from a container.
|
||||
if kind == AnnotationKind::Prohibited ||
|
||||
(kind == AnnotationKind::Container &&
|
||||
stab.level.is_stable() &&
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ pub struct ConstEvalErr<'tcx> {
|
|||
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub struct FrameInfo<'tcx> {
|
||||
pub call_site: Span, // this span is in the caller!
|
||||
/// This span is in the caller.
|
||||
pub call_site: Span,
|
||||
pub instance: ty::Instance<'tcx>,
|
||||
pub lint_root: Option<hir::HirId>,
|
||||
}
|
||||
|
|
@ -200,12 +201,12 @@ fn print_backtrace(backtrace: &mut Backtrace) {
|
|||
impl<'tcx> From<InterpError<'tcx, u64>> for EvalError<'tcx> {
|
||||
fn from(kind: InterpError<'tcx, u64>) -> Self {
|
||||
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
|
||||
// matching RUST_BACKTRACE, we treat "0" the same as "not present".
|
||||
// Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
|
||||
Ok(ref val) if val != "0" => {
|
||||
let mut backtrace = Backtrace::new_unresolved();
|
||||
|
||||
if val == "immediate" {
|
||||
// Print it now
|
||||
// Print it now.
|
||||
print_backtrace(&mut backtrace);
|
||||
None
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -662,7 +662,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
"{}",
|
||||
message.unwrap_or_else(||
|
||||
format!("the trait bound `{}` is not satisfied{}",
|
||||
trait_ref.to_predicate(), post_message)
|
||||
trait_ref.to_predicate(), post_message)
|
||||
));
|
||||
|
||||
let explanation =
|
||||
|
|
@ -676,7 +676,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
|
||||
if let Some(ref s) = label {
|
||||
// If it has a custom "#[rustc_on_unimplemented]"
|
||||
// If it has a custom `#[rustc_on_unimplemented]`
|
||||
// error message, let's display it as the label!
|
||||
err.span_label(span, s.as_str());
|
||||
err.help(&explanation);
|
||||
|
|
@ -684,7 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
err.span_label(span, explanation);
|
||||
}
|
||||
if let Some(ref s) = note {
|
||||
// If it has a custom "#[rustc_on_unimplemented]" note, let's display it
|
||||
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
|
||||
err.note(s.as_str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1465,9 +1465,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
let predicate = self.infcx()
|
||||
.resolve_vars_if_possible(&obligation.predicate);
|
||||
|
||||
// OK to skip binder because of the nature of the
|
||||
// Okay to skip binder because of the nature of the
|
||||
// trait-ref-is-knowable check, which does not care about
|
||||
// bound regions
|
||||
// bound regions.
|
||||
let trait_ref = predicate.skip_binder().trait_ref;
|
||||
|
||||
let result = coherence::trait_ref_is_knowable(self.tcx(), trait_ref);
|
||||
|
|
@ -1848,12 +1848,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
.iter()
|
||||
.filter_map(|o| o.to_opt_poly_trait_ref());
|
||||
|
||||
// micro-optimization: filter out predicates relating to different
|
||||
// traits.
|
||||
// Micro-optimization: filter out predicates relating to different traits.
|
||||
let matching_bounds =
|
||||
all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
|
||||
|
||||
// keep only those bounds which may apply, and propagate overflow if it occurs
|
||||
// Keep only those bounds which may apply, and propagate overflow if it occurs.
|
||||
let mut param_candidates = vec![];
|
||||
for bound in matching_bounds {
|
||||
let wc = self.evaluate_where_clause(stack, bound.clone())?;
|
||||
|
|
@ -1891,9 +1890,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
// OK to skip binder because the substs on generator types never
|
||||
// Okay to skip binder because the substs on generator types never
|
||||
// touch bound regions, they just capture the in-scope
|
||||
// type/region parameters
|
||||
// type/region parameters.
|
||||
let self_ty = *obligation.self_ty().skip_binder();
|
||||
match self_ty.sty {
|
||||
ty::Generator(..) => {
|
||||
|
|
@ -1935,7 +1934,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// OK to skip binder because the substs on closure types never
|
||||
// Okay to skip binder because the substs on closure types never
|
||||
// touch bound regions, they just capture the in-scope
|
||||
// type/region parameters
|
||||
match obligation.self_ty().skip_binder().sty {
|
||||
|
|
@ -1985,7 +1984,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
// OK to skip binder because what we are inspecting doesn't involve bound regions
|
||||
// Okay to skip binder because what we are inspecting doesn't involve bound regions
|
||||
let self_ty = *obligation.self_ty().skip_binder();
|
||||
match self_ty.sty {
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
|
|
@ -2042,7 +2041,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) -> Result<(), SelectionError<'tcx>> {
|
||||
// OK to skip binder here because the tests we do below do not involve bound regions
|
||||
// Okay to skip binder here because the tests we do below do not involve bound regions.
|
||||
let self_ty = *obligation.self_ty().skip_binder();
|
||||
debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
|
||||
|
||||
|
|
@ -2274,7 +2273,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) -> Result<(), SelectionError<'tcx>> {
|
||||
// OK to skip binder here because the tests we do below do not involve bound regions
|
||||
// Okay to skip binder here because the tests we do below do not involve bound regions.
|
||||
let self_ty = *obligation.self_ty().skip_binder();
|
||||
debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
|
||||
|
||||
|
|
@ -3094,7 +3093,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
debug!("confirm_fn_pointer_candidate({:?})", obligation);
|
||||
|
||||
// OK to skip binder; it is reintroduced below
|
||||
// Okay to skip binder; it is reintroduced below.
|
||||
let self_ty = self.infcx
|
||||
.shallow_resolve(*obligation.self_ty().skip_binder());
|
||||
let sig = self_ty.fn_sig(self.tcx());
|
||||
|
|
@ -3172,9 +3171,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
// OK to skip binder because the substs on generator types never
|
||||
// Okay to skip binder because the substs on generator types never
|
||||
// touch bound regions, they just capture the in-scope
|
||||
// type/region parameters
|
||||
// type/region parameters.
|
||||
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
|
||||
let (generator_def_id, substs) = match self_ty.sty {
|
||||
ty::Generator(id, substs, _) => (id, substs),
|
||||
|
|
@ -3229,9 +3228,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
.fn_trait_kind(obligation.predicate.def_id())
|
||||
.unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));
|
||||
|
||||
// OK to skip binder because the substs on closure types never
|
||||
// Okay to skip binder because the substs on closure types never
|
||||
// touch bound regions, they just capture the in-scope
|
||||
// type/region parameters
|
||||
// type/region parameters.
|
||||
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
|
||||
let (closure_def_id, substs) = match self_ty.sty {
|
||||
ty::Closure(id, substs) => (id, substs),
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ use std::fmt;
|
|||
use std::rc::Rc;
|
||||
use std::collections::{BTreeSet, BTreeMap};
|
||||
|
||||
// structural impls for the structs in traits
|
||||
// Structural impls for the structs in `traits`.
|
||||
|
||||
impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Normalized({:?},{:?})", self.value, self.obligations)
|
||||
write!(f, "Normalized({:?}, {:?})", self.value, self.obligations)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,13 +23,13 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
|
|||
if ty::tls::with(|tcx| tcx.sess.verbose()) {
|
||||
write!(
|
||||
f,
|
||||
"Obligation(predicate={:?},cause={:?},param_env={:?},depth={})",
|
||||
"Obligation(predicate={:?}, cause={:?}, param_env={:?}, depth={})",
|
||||
self.predicate, self.cause, self.param_env, self.recursion_depth
|
||||
)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"Obligation(predicate={:?},depth={})",
|
||||
"Obligation(predicate={:?}, depth={})",
|
||||
self.predicate, self.recursion_depth
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1706,21 +1706,21 @@ impl<'gcx> GlobalCtxt<'gcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A trait implemented for all X<'a> types which can be safely and
|
||||
/// efficiently converted to X<'tcx> as long as they are part of the
|
||||
/// provided TyCtxt<'tcx>.
|
||||
/// This can be done, for example, for Ty<'tcx> or SubstsRef<'tcx>
|
||||
/// A trait implemented for all `X<'a>` types that can be safely and
|
||||
/// efficiently converted to `X<'tcx>` as long as they are part of the
|
||||
/// provided `TyCtxt<'tcx>`.
|
||||
/// This can be done, for example, for `Ty<'tcx>` or `SubstsRef<'tcx>`
|
||||
/// by looking them up in their respective interners.
|
||||
///
|
||||
/// However, this is still not the best implementation as it does
|
||||
/// need to compare the components, even for interned values.
|
||||
/// It would be more efficient if TypedArena provided a way to
|
||||
/// It would be more efficient if `TypedArena` provided a way to
|
||||
/// determine whether the address is in the allocated range.
|
||||
///
|
||||
/// None is returned if the value or one of the components is not part
|
||||
/// of the provided context.
|
||||
/// For Ty, None can be returned if either the type interner doesn't
|
||||
/// contain the TyKind key or if the address of the interned
|
||||
/// For `Ty`, `None` can be returned if either the type interner doesn't
|
||||
/// contain the `TyKind` key or if the address of the interned
|
||||
/// pointer differs. The latter case is possible if a primitive type,
|
||||
/// e.g., `()` or `u8`, was interned in a different context.
|
||||
pub trait Lift<'tcx>: fmt::Debug {
|
||||
|
|
|
|||
|
|
@ -1090,7 +1090,7 @@ pub enum Predicate<'tcx> {
|
|||
/// See the `ProjectionPredicate` struct for details.
|
||||
Projection(PolyProjectionPredicate<'tcx>),
|
||||
|
||||
/// no syntax: `T` well-formed
|
||||
/// No syntax: `T` well-formed.
|
||||
WellFormed(Ty<'tcx>),
|
||||
|
||||
/// Trait must be object-safe.
|
||||
|
|
@ -1245,19 +1245,17 @@ impl<'tcx> TraitPredicate<'tcx> {
|
|||
|
||||
impl<'tcx> PolyTraitPredicate<'tcx> {
|
||||
pub fn def_id(&self) -> DefId {
|
||||
// ok to skip binder since trait def-id does not care about regions
|
||||
// Ok to skip binder since trait def-ID does not care about regions.
|
||||
self.skip_binder().def_id()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord,
|
||||
Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A: B`
|
||||
pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
|
||||
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>,
|
||||
ty::Region<'tcx>>;
|
||||
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>,
|
||||
ty::Region<'tcx>>;
|
||||
pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
|
||||
pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>;
|
||||
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
|
||||
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
|
||||
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>;
|
||||
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<TypeOutlivesPredicate<'tcx>>;
|
||||
|
||||
|
|
@ -1314,7 +1312,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
|
|||
/// Note that this is not the `DefId` of the `TraitRef` containing this
|
||||
/// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
|
||||
pub fn projection_def_id(&self) -> DefId {
|
||||
// okay to skip binder since trait def-id does not care about regions
|
||||
// Ok to skip binder since trait def-ID does not care about regions.
|
||||
self.skip_binder().projection_ty.item_def_id
|
||||
}
|
||||
}
|
||||
|
|
@ -1371,7 +1369,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// A custom iterator used by Predicate::walk_tys.
|
||||
// A custom iterator used by `Predicate::walk_tys`.
|
||||
enum WalkTysIter<'tcx, I, J, K>
|
||||
where I: Iterator<Item = Ty<'tcx>>,
|
||||
J: Iterator<Item = Ty<'tcx>>,
|
||||
|
|
@ -1505,7 +1503,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
///
|
||||
/// Example:
|
||||
///
|
||||
/// struct Foo<T,U:Bar<T>> { ... }
|
||||
/// struct Foo<T, U: Bar<T>> { ... }
|
||||
///
|
||||
/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like
|
||||
/// `[[], [U:Bar<T>]]`. Now if there were some particular reference
|
||||
|
|
@ -2785,10 +2783,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
e.span
|
||||
}
|
||||
Some(f) => {
|
||||
bug!("Node id {} is not an expr: {:?}", id, f);
|
||||
bug!("node-ID {} is not an expr: {:?}", id, f);
|
||||
}
|
||||
None => {
|
||||
bug!("Node id {} is not present in the node map", id);
|
||||
bug!("node-ID {} is not present in the node map", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,12 +96,12 @@ pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
|
||||
/// Either gets a JobOwner corresponding the query, allowing us to
|
||||
/// Either gets a `JobOwner` corresponding the query, allowing us to
|
||||
/// start executing the query, or it returns with the result of the query.
|
||||
/// If the query is executing elsewhere, this will wait for it.
|
||||
/// If the query panicked, this will silently panic.
|
||||
///
|
||||
/// This function is inlined because that results in a noticeable speedup
|
||||
/// This function is inlined because that results in a noticeable speed-up
|
||||
/// for some compile-time benchmarks.
|
||||
#[inline(always)]
|
||||
pub(super) fn try_get(
|
||||
|
|
@ -126,9 +126,9 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
|
|||
Entry::Occupied(entry) => {
|
||||
match *entry.get() {
|
||||
QueryResult::Started(ref job) => {
|
||||
//For parallel queries, we'll block and wait until the query running
|
||||
//in another thread has completed. Record how long we wait in the
|
||||
//self-profiler
|
||||
// For parallel queries, we'll block and wait until the query running
|
||||
// in another thread has completed. Record how long we wait in the
|
||||
// self-profiler.
|
||||
#[cfg(parallel_compiler)]
|
||||
tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME));
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
|
|||
}
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
// No job entry for this query. Return a new one to be started later
|
||||
// No job entry for this query. Return a new one to be started later.
|
||||
return tls::with_related_context(tcx, |icx| {
|
||||
// Create the `parent` variable before `info`. This allows LLVM
|
||||
// to elide the move of `info`
|
||||
|
|
@ -161,14 +161,14 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
|
|||
mem::drop(lock);
|
||||
|
||||
// If we are single-threaded we know that we have cycle error,
|
||||
// so we just return the error
|
||||
// so we just return the error.
|
||||
#[cfg(not(parallel_compiler))]
|
||||
return TryGetJob::Cycle(cold_path(|| {
|
||||
Q::handle_cycle_error(tcx, job.find_cycle_in_stack(tcx, span))
|
||||
}));
|
||||
|
||||
// With parallel queries we might just have to wait on some other
|
||||
// thread
|
||||
// thread.
|
||||
#[cfg(parallel_compiler)]
|
||||
{
|
||||
let result = job.r#await(tcx, span);
|
||||
|
|
@ -636,8 +636,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
profq_query_msg!(Q::NAME.as_str(), self, key))
|
||||
);
|
||||
|
||||
// We may be concurrently trying both execute and force a query
|
||||
// Ensure that only one of them runs the query
|
||||
// We may be concurrently trying both execute and force a query.
|
||||
// Ensure that only one of them runs the query.
|
||||
let job = match JobOwner::try_get(self, span, &key) {
|
||||
TryGetJob::NotYetStarted(job) => job,
|
||||
TryGetJob::Cycle(_) |
|
||||
|
|
@ -731,7 +731,7 @@ macro_rules! define_queries_inner {
|
|||
let mut jobs = Vec::new();
|
||||
|
||||
// We use try_lock here since we are only called from the
|
||||
// deadlock handler, and this shouldn't be locked
|
||||
// deadlock handler, and this shouldn't be locked.
|
||||
$(
|
||||
jobs.extend(
|
||||
self.$name.try_lock().unwrap().active.values().filter_map(|v|
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
self.def_key(def_id).disambiguated_data.data == DefPathData::Ctor
|
||||
}
|
||||
|
||||
/// Given the `DefId` of a fn or closure, returns the `DefId` of
|
||||
/// Given the def-ID of a fn or closure, returns the def-ID of
|
||||
/// the innermost fn item that the closure is contained within.
|
||||
/// This is a significant `DefId` because, when we do
|
||||
/// type-checking, we type-check this fn item and all of its
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::dep_graph::{DepNode};
|
|||
use lazy_static;
|
||||
use crate::session::Session;
|
||||
|
||||
// The name of the associated type for `Fn` return types
|
||||
// The name of the associated type for `Fn` return types.
|
||||
pub const FN_OUTPUT_NAME: Symbol = sym::Output;
|
||||
|
||||
// Useful type to use with `Result<>` indicate that an error has already
|
||||
|
|
@ -45,16 +45,16 @@ fn panic_hook(info: &panic::PanicInfo<'_>) {
|
|||
TyCtxt::try_print_query_stack();
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
|
||||
extern "system" {
|
||||
fn DebugBreak();
|
||||
}
|
||||
// Trigger a debugger if we crashed during bootstrap
|
||||
DebugBreak();
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
|
||||
extern "system" {
|
||||
fn DebugBreak();
|
||||
}
|
||||
// Trigger a debugger if we crashed during bootstrap.
|
||||
DebugBreak();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install_panic_hook() {
|
||||
|
|
@ -80,42 +80,42 @@ pub struct QueryMsg {
|
|||
}
|
||||
|
||||
/// A sequence of these messages induce a trace of query-based incremental compilation.
|
||||
/// FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
|
||||
// FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
|
||||
#[derive(Clone,Debug)]
|
||||
pub enum ProfileQueriesMsg {
|
||||
/// begin a timed pass
|
||||
/// Begin a timed pass.
|
||||
TimeBegin(String),
|
||||
/// end a timed pass
|
||||
/// End a timed pass.
|
||||
TimeEnd,
|
||||
/// begin a task (see dep_graph::graph::with_task)
|
||||
/// Begin a task (see `dep_graph::graph::with_task`).
|
||||
TaskBegin(DepNode),
|
||||
/// end a task
|
||||
/// End a task.
|
||||
TaskEnd,
|
||||
/// begin a new query
|
||||
/// can't use `Span` because queries are sent to other thread
|
||||
/// Begin a new query.
|
||||
/// Cannot use `Span` because queries are sent to other thread.
|
||||
QueryBegin(SpanData, QueryMsg),
|
||||
/// query is satisfied by using an already-known value for the given key
|
||||
/// Query is satisfied by using an already-known value for the given key.
|
||||
CacheHit,
|
||||
/// query requires running a provider; providers may nest, permitting queries to nest.
|
||||
/// Query requires running a provider; providers may nest, permitting queries to nest.
|
||||
ProviderBegin,
|
||||
/// query is satisfied by a provider terminating with a value
|
||||
/// Query is satisfied by a provider terminating with a value.
|
||||
ProviderEnd,
|
||||
/// dump a record of the queries to the given path
|
||||
/// Dump a record of the queries to the given path.
|
||||
Dump(ProfQDumpParams),
|
||||
/// halt the profiling/monitoring background thread
|
||||
/// Halt the profiling/monitoring background thread.
|
||||
Halt
|
||||
}
|
||||
|
||||
/// If enabled, send a message to the profile-queries thread
|
||||
/// If enabled, send a message to the profile-queries thread.
|
||||
pub fn profq_msg(sess: &Session, msg: ProfileQueriesMsg) {
|
||||
if let Some(s) = sess.profile_channel.borrow().as_ref() {
|
||||
s.send(msg).unwrap()
|
||||
} else {
|
||||
// Do nothing
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
/// Set channel for profile queries channel
|
||||
/// Set channel for profile queries channel.
|
||||
pub fn profq_set_chan(sess: &Session, s: Sender<ProfileQueriesMsg>) -> bool {
|
||||
let mut channel = sess.profile_channel.borrow_mut();
|
||||
if channel.is_none() {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use rustc::hir;
|
|||
use rustc::hir::intravisit;
|
||||
use rustc::hir::print as pprust;
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum EntryOrExit {
|
||||
Entry,
|
||||
|
|
@ -92,7 +91,7 @@ fn get_cfg_indices<'a>(id: hir::ItemLocalId,
|
|||
index.get(&id).map_or(&[], |v| &v[..])
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
|
||||
impl<'a, 'tcx, O: DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
|
||||
fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool {
|
||||
assert!(n != hir::DUMMY_ITEM_LOCAL_ID);
|
||||
self.local_id_to_index.contains_key(&n)
|
||||
|
|
@ -225,7 +224,7 @@ pub enum KillFrom {
|
|||
Execution,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
|
||||
impl<'a, 'tcx, O: DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
analysis_name: &'static str,
|
||||
body: Option<&hir::Body>,
|
||||
|
|
@ -500,8 +499,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
|
||||
// ^^^^^^^^^^^^^ only needed for pretty printing
|
||||
// N.B. `Clone + 'static` only needed for pretty printing.
|
||||
impl<'a, 'tcx, O: DataFlowOperator + Clone + 'static> DataFlowContext<'a, 'tcx, O> {
|
||||
pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
|
||||
//! Performs the data flow analysis.
|
||||
|
||||
|
|
@ -538,7 +537,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
|
||||
impl<'a, 'b, 'tcx, O: DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
|
||||
fn walk_cfg(&mut self,
|
||||
cfg: &cfg::CFG,
|
||||
nodes_po: &[CFGIndex],
|
||||
|
|
@ -547,7 +546,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
|
|||
bits_to_string(in_out), self.dfcx.analysis_name);
|
||||
assert!(self.dfcx.bits_per_id > 0);
|
||||
|
||||
// Iterate over nodes in reverse postorder
|
||||
// Iterate over nodes in reverse post-order.
|
||||
for &node_index in nodes_po.iter().rev() {
|
||||
let node = cfg.graph.node(node_index);
|
||||
debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}",
|
||||
|
|
@ -631,9 +630,9 @@ fn bits_to_string(words: &[usize]) -> String {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
|
||||
in_vec: &[usize],
|
||||
op: &Op) -> bool {
|
||||
fn bitwise<Op: BitwiseOperator>(out_vec: &mut [usize],
|
||||
in_vec: &[usize],
|
||||
op: &Op) -> bool {
|
||||
assert_eq!(out_vec.len(), in_vec.len());
|
||||
let mut changed = false;
|
||||
for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
|
||||
|
|
|
|||
|
|
@ -937,8 +937,8 @@ fn codegen_msvc_try(
|
|||
bx.store(ret, dest, i32_align);
|
||||
}
|
||||
|
||||
// Definition of the standard "try" function for Rust using the GNU-like model
|
||||
// of exceptions (e.g., the normal semantics of LLVM's landingpad and invoke
|
||||
// Definition of the standard `try` function for Rust using the GNU-like model
|
||||
// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
|
||||
// instructions).
|
||||
//
|
||||
// This codegen is a little surprising because we always call a shim
|
||||
|
|
|
|||
|
|
@ -1127,10 +1127,10 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker,
|
|||
// For this reason, we have organized the arguments we pass to the linker as
|
||||
// such:
|
||||
//
|
||||
// 1. The local object that LLVM just generated
|
||||
// 2. Local native libraries
|
||||
// 3. Upstream rust libraries
|
||||
// 4. Upstream native libraries
|
||||
// 1. The local object that LLVM just generated
|
||||
// 2. Local native libraries
|
||||
// 3. Upstream rust libraries
|
||||
// 4. Upstream native libraries
|
||||
//
|
||||
// The rationale behind this ordering is that those items lower down in the
|
||||
// list can't depend on items higher up in the list. For example nothing can
|
||||
|
|
|
|||
|
|
@ -967,7 +967,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.range_metadata(llval, 0..2);
|
||||
}
|
||||
}
|
||||
// We store bools as i8 so we need to truncate to i1.
|
||||
// We store bools as `i8` so we need to truncate to `i1`.
|
||||
llval = base::to_immediate(bx, llval, arg.layout);
|
||||
}
|
||||
}
|
||||
|
|
@ -1097,7 +1097,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
fn_ret: &ArgType<'tcx, Ty<'tcx>>,
|
||||
llargs: &mut Vec<Bx::Value>, is_intrinsic: bool
|
||||
) -> ReturnDest<'tcx, Bx::Value> {
|
||||
// If the return is ignored, we can just return a do-nothing ReturnDest
|
||||
// If the return is ignored, we can just return a do-nothing `ReturnDest`.
|
||||
if fn_ret.is_ignore() {
|
||||
return ReturnDest::Nothing;
|
||||
}
|
||||
|
|
@ -1106,8 +1106,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
LocalRef::Place(dest) => dest,
|
||||
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
|
||||
LocalRef::Operand(None) => {
|
||||
// Handle temporary places, specifically Operand ones, as
|
||||
// they don't have allocas
|
||||
// Handle temporary places, specifically `Operand` ones, as
|
||||
// they don't have `alloca`s.
|
||||
return if fn_ret.is_indirect() {
|
||||
// Odd, but possible, case, we have an operand temporary,
|
||||
// but the calling convention has an indirect return.
|
||||
|
|
@ -1117,8 +1117,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
ReturnDest::IndirectOperand(tmp, index)
|
||||
} else if is_intrinsic {
|
||||
// Currently, intrinsics always need a location to store
|
||||
// the result. so we create a temporary alloca for the
|
||||
// result
|
||||
// the result, so we create a temporary `alloca` for the
|
||||
// result.
|
||||
let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
|
||||
tmp.storage_live(bx);
|
||||
ReturnDest::IndirectOperand(tmp, index)
|
||||
|
|
@ -1137,7 +1137,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
if dest.align < dest.layout.align.abi {
|
||||
// Currently, MIR code generation does not create calls
|
||||
// that store directly to fields of packed structs (in
|
||||
// fact, the calls it creates write only to temps),
|
||||
// fact, the calls it creates write only to temps).
|
||||
//
|
||||
// If someone changes that, please update this code path
|
||||
// to create a temporary.
|
||||
|
|
@ -1232,12 +1232,12 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
enum ReturnDest<'tcx, V> {
|
||||
// Do nothing, the return value is indirect or ignored
|
||||
// Do nothing; the return value is indirect or ignored.
|
||||
Nothing,
|
||||
// Store the return value to the pointer
|
||||
// Store the return value to the pointer.
|
||||
Store(PlaceRef<'tcx, V>),
|
||||
// Stores an indirect return value to an operand local place
|
||||
// Store an indirect return value to an operand local place.
|
||||
IndirectOperand(PlaceRef<'tcx, V>, mir::Local),
|
||||
// Stores a direct return value to an operand local place
|
||||
// Store a direct return value to an operand local place.
|
||||
DirectOperand(mir::Local)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix))
|
||||
};
|
||||
PlaceRef {
|
||||
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
|
||||
// HACK(eddyb): have to bitcast pointers until LLVM removes pointee types.
|
||||
llval: bx.pointercast(llval, bx.cx().type_ptr_to(bx.cx().backend_type(field))),
|
||||
llextra: if bx.cx().type_has_metadata(field.ty) {
|
||||
self.llextra
|
||||
|
|
@ -134,7 +134,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
|
||||
// Simple cases, which don't need DST adjustment:
|
||||
// * no metadata available - just log the case
|
||||
// * known alignment - sized types, [T], str or a foreign type
|
||||
// * known alignment - sized types, `[T]`, `str` or a foreign type
|
||||
// * packed struct - there is no alignment padding
|
||||
match field.ty.sty {
|
||||
_ if self.llextra.is_none() => {
|
||||
|
|
@ -156,18 +156,19 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
}
|
||||
|
||||
// We need to get the pointer manually now.
|
||||
// We do this by casting to a *i8, then offsetting it by the appropriate amount.
|
||||
// We do this by casting to a `*i8`, then offsetting it by the appropriate amount.
|
||||
// We do this instead of, say, simply adjusting the pointer from the result of a GEP
|
||||
// because the field may have an arbitrary alignment in the LLVM representation
|
||||
// anyway.
|
||||
//
|
||||
// To demonstrate:
|
||||
// struct Foo<T: ?Sized> {
|
||||
// x: u16,
|
||||
// y: T
|
||||
// }
|
||||
//
|
||||
// The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
|
||||
// struct Foo<T: ?Sized> {
|
||||
// x: u16,
|
||||
// y: T
|
||||
// }
|
||||
//
|
||||
// The type `Foo<Foo<Trait>>` is represented in LLVM as `{ u16, { u16, u8 }}`, meaning that
|
||||
// the `y` field has 16-bit alignment.
|
||||
|
||||
let meta = self.llextra;
|
||||
|
|
@ -180,9 +181,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
// Bump the unaligned offset up to the appropriate alignment using the
|
||||
// following expression:
|
||||
//
|
||||
// (unaligned offset + (align - 1)) & -align
|
||||
// (unaligned offset + (align - 1)) & -align
|
||||
|
||||
// Calculate offset
|
||||
// Calculate offset.
|
||||
let align_sub_1 = bx.sub(unsized_align, bx.cx().const_usize(1u64));
|
||||
let and_lhs = bx.add(unaligned_offset, align_sub_1);
|
||||
let and_rhs = bx.neg(unsized_align);
|
||||
|
|
@ -190,11 +191,11 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
|
||||
debug!("struct_field_ptr: DST field offset: {:?}", offset);
|
||||
|
||||
// Cast and adjust pointer
|
||||
// Cast and adjust pointer.
|
||||
let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
|
||||
let byte_ptr = bx.gep(byte_ptr, &[offset]);
|
||||
|
||||
// Finally, cast back to the type expected
|
||||
// Finally, cast back to the type expected.
|
||||
let ll_fty = bx.cx().backend_type(field);
|
||||
debug!("struct_field_ptr: Field type is {:?}", ll_fty);
|
||||
|
||||
|
|
@ -235,7 +236,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
// We use `i1` for bytes that are always `0` or `1`,
|
||||
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
|
||||
// let LLVM interpret the `i1` as signed, because
|
||||
// then `i1 1` (i.e., E::B) is effectively `i8 -1`.
|
||||
// then `i1 1` (i.e., `E::B`) is effectively `i8 -1`.
|
||||
layout::Int(_, signed) => !discr_scalar.is_bool() && signed,
|
||||
_ => false
|
||||
};
|
||||
|
|
@ -248,9 +249,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
} => {
|
||||
let niche_llty = bx.cx().immediate_backend_type(discr.layout);
|
||||
if niche_variants.start() == niche_variants.end() {
|
||||
// FIXME(eddyb) Check the actual primitive type here.
|
||||
// FIXME(eddyb): check the actual primitive type here.
|
||||
let niche_llval = if niche_start == 0 {
|
||||
// HACK(eddyb) Using `c_null` as it works on all types.
|
||||
// HACK(eddyb): using `c_null` as it works on all types.
|
||||
bx.cx().const_null(niche_llty)
|
||||
} else {
|
||||
bx.cx().const_uint_big(niche_llty, niche_start)
|
||||
|
|
@ -314,7 +315,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
if variant_index != dataful_variant {
|
||||
if bx.cx().sess().target.target.arch == "arm" ||
|
||||
bx.cx().sess().target.target.arch == "aarch64" {
|
||||
// Issue #34427: As workaround for LLVM bug on ARM,
|
||||
// FIXME(#34427): as workaround for LLVM bug on ARM,
|
||||
// use memset of 0 before assigning niche value.
|
||||
let fill_byte = bx.cx().const_u8(0);
|
||||
let size = bx.cx().const_usize(self.layout.size.bytes());
|
||||
|
|
@ -326,9 +327,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
|
||||
let niche_value = (niche_value as u128)
|
||||
.wrapping_add(niche_start);
|
||||
// FIXME(eddyb) Check the actual primitive type here.
|
||||
// FIXME(eddyb): check the actual primitive type here.
|
||||
let niche_llval = if niche_value == 0 {
|
||||
// HACK(eddyb) Using `c_null` as it works on all types.
|
||||
// HACK(eddyb): using `c_null` as it works on all types.
|
||||
bx.cx().const_null(niche_llty)
|
||||
} else {
|
||||
bx.cx().const_uint_big(niche_llty, niche_value)
|
||||
|
|
@ -429,10 +430,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
_ => bug!("promoteds should have an allocation: {:?}", val),
|
||||
},
|
||||
Err(_) => {
|
||||
// this is unreachable as long as runtime
|
||||
// This is unreachable as long as runtime
|
||||
// and compile-time agree on values
|
||||
// With floats that won't always be true
|
||||
// so we generate an abort
|
||||
// With floats that won't always be true,
|
||||
// so we generate an abort.
|
||||
bx.abort();
|
||||
let llval = bx.cx().const_undef(
|
||||
bx.cx().type_ptr_to(bx.cx().backend_type(layout))
|
||||
|
|
@ -502,7 +503,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
// Cast the place pointer type to the new
|
||||
// array or slice type (*[%_; new_len]).
|
||||
// array or slice type (`*[%_; new_len]`).
|
||||
subslice.llval = bx.pointercast(subslice.llval,
|
||||
bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)));
|
||||
|
||||
|
|
|
|||
|
|
@ -717,7 +717,13 @@ impl<'a> ReplaceBodyWithLoop<'a> {
|
|||
_ => None,
|
||||
});
|
||||
any_involves_impl_trait(types.into_iter()) ||
|
||||
any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty))
|
||||
data.constraints.iter().any(|c| {
|
||||
match c.kind {
|
||||
ast::AssocTyConstraintKind::Bound { .. } => true,
|
||||
ast::AssocTyConstraintKind::Equality { ref ty } =>
|
||||
involves_impl_trait(ty),
|
||||
}
|
||||
})
|
||||
},
|
||||
Some(&ast::GenericArgs::Parenthesized(ref data)) => {
|
||||
any_involves_impl_trait(data.inputs.iter()) ||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
|
|||
|
||||
impl UnsafeCode {
|
||||
fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, desc: &'static str) {
|
||||
// This comes from a macro that has #[allow_internal_unsafe].
|
||||
// This comes from a macro that has `#[allow_internal_unsafe]`.
|
||||
if span.allows_unsafe() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -216,7 +216,7 @@ impl EarlyLintPass for UnsafeCode {
|
|||
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
if let ast::ExprKind::Block(ref blk, _) = e.node {
|
||||
// Don't warn about generated blocks, that'll just pollute the output.
|
||||
// Don't warn about generated blocks; that'll just pollute the output.
|
||||
if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
|
||||
self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
|
||||
}
|
||||
|
|
@ -335,7 +335,7 @@ impl MissingDoc {
|
|||
|
||||
// Only check publicly-visible items, using the result from the privacy pass.
|
||||
// It's an option so the crate root can also use this function (it doesn't
|
||||
// have a NodeId).
|
||||
// have a `NodeId`).
|
||||
if let Some(id) = id {
|
||||
if !cx.access_levels.is_exported(id) {
|
||||
return;
|
||||
|
|
@ -389,7 +389,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
|||
hir::ItemKind::Struct(..) => "a struct",
|
||||
hir::ItemKind::Union(..) => "a union",
|
||||
hir::ItemKind::Trait(.., ref trait_item_refs) => {
|
||||
// Issue #11592, traits are always considered exported, even when private.
|
||||
// Issue #11592: traits are always considered exported, even when private.
|
||||
if let hir::VisibilityKind::Inherited = it.vis.node {
|
||||
self.private_traits.insert(it.hir_id);
|
||||
for trait_item_ref in trait_item_refs {
|
||||
|
|
@ -401,7 +401,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
|||
}
|
||||
hir::ItemKind::Ty(..) => "a type alias",
|
||||
hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) => {
|
||||
// If the trait is private, add the impl items to private_traits so they don't get
|
||||
// If the trait is private, add the impl items to `private_traits` so they don't get
|
||||
// reported for missing docs.
|
||||
let real_trait = trait_ref.path.res.def_id();
|
||||
if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(real_trait) {
|
||||
|
|
@ -1215,7 +1215,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
|||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::Predicate::*;
|
||||
|
||||
|
||||
if cx.tcx.features().trivial_bounds {
|
||||
let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
|
||||
let predicates = cx.tcx.predicates_of(def_id);
|
||||
|
|
@ -1464,7 +1463,7 @@ impl KeywordIdents {
|
|||
_ => return,
|
||||
};
|
||||
|
||||
// don't lint `r#foo`
|
||||
// Don't lint `r#foo`.
|
||||
if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1717,8 +1716,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
|
|||
);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// Adds a suggestion to errors where a `impl Trait` is returned.
|
||||
///
|
||||
/// ```text
|
||||
/// help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as
|
||||
/// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
|
||||
/// a constraint
|
||||
/// |
|
||||
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
|
||||
|
|
@ -652,7 +652,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
diag.span_suggestion(
|
||||
span,
|
||||
&format!(
|
||||
"to allow this impl Trait to capture borrowed data with lifetime \
|
||||
"to allow this `impl Trait` to capture borrowed data with lifetime \
|
||||
`{}`, add `{}` as a constraint",
|
||||
fr_name, suggestable_fr_name,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -289,9 +289,9 @@ pub enum BlockFrame {
|
|||
/// Evaluation is currently within a statement.
|
||||
///
|
||||
/// Examples include:
|
||||
/// 1. `EXPR;`
|
||||
/// 2. `let _ = EXPR;`
|
||||
/// 3. `let x = EXPR;`
|
||||
/// 1. `EXPR;`
|
||||
/// 2. `let _ = EXPR;`
|
||||
/// 3. `let x = EXPR;`
|
||||
Statement {
|
||||
/// If true, then statement discards result from evaluating
|
||||
/// the expression (such as examples 1 and 2 above).
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
//!
|
||||
//! Note though that as a side-effect of creating a codegen units per
|
||||
//! source-level module, functions from the same module will be available for
|
||||
//! inlining, even when they are not marked #[inline].
|
||||
//! inlining, even when they are not marked `#[inline]`.
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::cmp;
|
||||
|
|
@ -152,7 +152,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
// In the next step, we use the inlining map to determine which additional
|
||||
// monomorphizations have to go into each codegen unit. These additional
|
||||
// monomorphizations can be drop-glue, functions from external crates, and
|
||||
// local functions the definition of which is marked with #[inline].
|
||||
// local functions the definition of which is marked with `#[inline]`.
|
||||
let mut post_inlining = place_inlined_mono_items(initial_partitioning,
|
||||
inlining_map);
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
internalize_symbols(tcx, &mut post_inlining, inlining_map);
|
||||
}
|
||||
|
||||
// Finally, sort by codegen unit name, so that we get deterministic results
|
||||
// Finally, sort by codegen unit name, so that we get deterministic results.
|
||||
let PostInliningPartitioning {
|
||||
codegen_units: mut result,
|
||||
mono_item_placements: _,
|
||||
|
|
@ -258,8 +258,8 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
roots.insert(mono_item);
|
||||
}
|
||||
|
||||
// always ensure we have at least one CGU; otherwise, if we have a
|
||||
// crate with just types (for example), we could wind up with no CGU
|
||||
// Always ensure we have at least one CGU; otherwise, if we have a
|
||||
// crate with just types (for example), we could wind up with no CGU.
|
||||
if codegen_units.is_empty() {
|
||||
let codegen_unit_name = fallback_cgu_name(cgu_name_builder);
|
||||
codegen_units.insert(codegen_unit_name.clone(),
|
||||
|
|
@ -300,10 +300,10 @@ fn mono_item_visibility(
|
|||
export_generics: bool,
|
||||
) -> Visibility {
|
||||
let instance = match mono_item {
|
||||
// This is pretty complicated, go below
|
||||
// This is pretty complicated; see below.
|
||||
MonoItem::Fn(instance) => instance,
|
||||
|
||||
// Misc handling for generics and such, but otherwise
|
||||
// Misc handling for generics and such, but otherwise:
|
||||
MonoItem::Static(def_id) => {
|
||||
return if tcx.is_reachable_non_generic(*def_id) {
|
||||
*can_be_internalized = false;
|
||||
|
|
@ -358,11 +358,10 @@ fn mono_item_visibility(
|
|||
|
||||
let is_generic = instance.substs.non_erasable_generics().next().is_some();
|
||||
|
||||
// Upstream `DefId` instances get different handling than local ones
|
||||
// Upstream `DefId` instances get different handling than local ones.
|
||||
if !def_id.is_local() {
|
||||
return if export_generics && is_generic {
|
||||
// If it is a upstream monomorphization
|
||||
// and we export generics, we must make
|
||||
// If it is a upstream monomorphization and we export generics, we must make
|
||||
// it available to downstream crates.
|
||||
*can_be_internalized = false;
|
||||
default_visibility(tcx, def_id, true)
|
||||
|
|
@ -374,20 +373,16 @@ fn mono_item_visibility(
|
|||
if is_generic {
|
||||
if export_generics {
|
||||
if tcx.is_unreachable_local_definition(def_id) {
|
||||
// This instance cannot be used
|
||||
// from another crate.
|
||||
// This instance cannot be used from another crate.
|
||||
Visibility::Hidden
|
||||
} else {
|
||||
// This instance might be useful in
|
||||
// a downstream crate.
|
||||
// This instance might be useful in a downstream crate.
|
||||
*can_be_internalized = false;
|
||||
default_visibility(tcx, def_id, true)
|
||||
}
|
||||
} else {
|
||||
// We are not exporting generics or
|
||||
// the definition is not reachable
|
||||
// for downstream crates, we can
|
||||
// internalize its instantiations.
|
||||
// We are not exporting generics or the definition is not reachable
|
||||
// for downstream crates, we can internalize its instantiations.
|
||||
Visibility::Hidden
|
||||
}
|
||||
} else {
|
||||
|
|
@ -449,19 +444,19 @@ fn default_visibility(tcx: TyCtxt<'_, '_, '_>, id: DefId, is_generic: bool) -> V
|
|||
return Visibility::Default
|
||||
}
|
||||
|
||||
// Generic functions never have export level C
|
||||
// Generic functions never have export-level C.
|
||||
if is_generic {
|
||||
return Visibility::Hidden
|
||||
}
|
||||
|
||||
// Things with export level C don't get instantiated in
|
||||
// downstream crates
|
||||
// downstream crates.
|
||||
if !id.is_local() {
|
||||
return Visibility::Hidden
|
||||
}
|
||||
|
||||
// C-export level items remain at `Default`, all other internal
|
||||
// items become `Hidden`
|
||||
// items become `Hidden`.
|
||||
match tcx.reachable_non_generics(id.krate).get(&id) {
|
||||
Some(SymbolExportLevel::C) => Visibility::Default,
|
||||
_ => Visibility::Hidden,
|
||||
|
|
@ -519,7 +514,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
|
|||
let single_codegen_unit = initial_cgus.len() == 1;
|
||||
|
||||
for old_codegen_unit in initial_cgus {
|
||||
// Collect all items that need to be available in this codegen unit
|
||||
// Collect all items that need to be available in this codegen unit.
|
||||
let mut reachable = FxHashSet::default();
|
||||
for root in old_codegen_unit.items().keys() {
|
||||
follow_inlining(*root, inlining_map, &mut reachable);
|
||||
|
|
@ -527,10 +522,10 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
|
|||
|
||||
let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name().clone());
|
||||
|
||||
// Add all monomorphizations that are not already there
|
||||
// Add all monomorphizations that are not already there.
|
||||
for mono_item in reachable {
|
||||
if let Some(linkage) = old_codegen_unit.items().get(&mono_item) {
|
||||
// This is a root, just copy it over
|
||||
// This is a root, just copy it over.
|
||||
new_codegen_unit.items_mut().insert(mono_item, *linkage);
|
||||
} else {
|
||||
if roots.contains(&mono_item) {
|
||||
|
|
@ -538,7 +533,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
|
|||
{:?}", mono_item);
|
||||
}
|
||||
|
||||
// This is a cgu-private copy
|
||||
// This is a CGU-private copy.
|
||||
new_codegen_unit.items_mut().insert(
|
||||
mono_item,
|
||||
(Linkage::Internal, Visibility::Default),
|
||||
|
|
@ -547,7 +542,7 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
|
|||
|
||||
if !single_codegen_unit {
|
||||
// If there is more than one codegen unit, we need to keep track
|
||||
// in which codegen units each monomorphization is placed:
|
||||
// in which codegen units each monomorphization is placed.
|
||||
match mono_item_placements.entry(mono_item) {
|
||||
Entry::Occupied(e) => {
|
||||
let placement = e.into_mut();
|
||||
|
|
@ -656,8 +651,8 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
}
|
||||
|
||||
fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mono_item: MonoItem<'tcx>)
|
||||
-> Option<DefId> {
|
||||
mono_item: MonoItem<'tcx>)
|
||||
-> Option<DefId> {
|
||||
match mono_item {
|
||||
MonoItem::Fn(instance) => {
|
||||
let def_id = match instance.def {
|
||||
|
|
@ -709,10 +704,10 @@ fn compute_codegen_unit_name(tcx: TyCtxt<'_, '_, '_>,
|
|||
volatile: bool,
|
||||
cache: &mut CguNameCache)
|
||||
-> InternedString {
|
||||
// Find the innermost module that is not nested within a function
|
||||
// Find the innermost module that is not nested within a function.
|
||||
let mut current_def_id = def_id;
|
||||
let mut cgu_def_id = None;
|
||||
// Walk backwards from the item we want to find the module for:
|
||||
// Walk backwards from the item we want to find the module for.
|
||||
loop {
|
||||
if current_def_id.index == CRATE_DEF_INDEX {
|
||||
if cgu_def_id.is_none() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Validate AST before lowering it to HIR
|
||||
// Validate AST before lowering it to HIR.
|
||||
//
|
||||
// This pass is supposed to catch things that fit into AST data structures,
|
||||
// but not permitted by the language. It runs after expansion when AST is frozen,
|
||||
|
|
@ -56,13 +56,17 @@ struct AstValidator<'a> {
|
|||
|
||||
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
|
||||
/// Nested `impl Trait` _is_ allowed in associated type position,
|
||||
/// e.g `impl Iterator<Item=impl Debug>`
|
||||
/// e.g., `impl Iterator<Item = impl Debug>`.
|
||||
outer_impl_trait: Option<OuterImplTrait>,
|
||||
|
||||
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
|
||||
/// or `Foo::Bar<impl Trait>`
|
||||
is_impl_trait_banned: bool,
|
||||
|
||||
/// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
|
||||
/// certain positions.
|
||||
is_assoc_ty_bound_banned: bool,
|
||||
|
||||
/// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
|
||||
/// until PRs #57730 and #57981 landed: it would jump directly to
|
||||
/// walk_ty rather than visit_ty (or skip recurring entirely for
|
||||
|
|
@ -87,26 +91,43 @@ impl<'a> AstValidator<'a> {
|
|||
self.is_impl_trait_banned = old;
|
||||
}
|
||||
|
||||
fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
|
||||
f(self);
|
||||
self.is_assoc_ty_bound_banned = old;
|
||||
}
|
||||
|
||||
fn with_impl_trait(&mut self, outer: Option<OuterImplTrait>, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.outer_impl_trait, outer);
|
||||
f(self);
|
||||
self.outer_impl_trait = old;
|
||||
}
|
||||
|
||||
fn visit_assoc_type_binding_from_generic_args(&mut self, type_binding: &'a TypeBinding) {
|
||||
// rust-lang/rust#57979: bug in old visit_generic_args called
|
||||
// walk_ty rather than visit_ty, skipping outer `impl Trait`
|
||||
// if it happened to occur at `type_binding.ty`
|
||||
if let TyKind::ImplTrait(..) = type_binding.ty.node {
|
||||
self.warning_period_57979_didnt_record_next_impl_trait = true;
|
||||
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
|
||||
match constraint.kind {
|
||||
AssocTyConstraintKind::Equality { ref ty } => {
|
||||
// rust-lang/rust#57979: bug in old `visit_generic_args` called
|
||||
// `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
|
||||
// if it happened to occur at `ty`.
|
||||
if let TyKind::ImplTrait(..) = ty.node {
|
||||
self.warning_period_57979_didnt_record_next_impl_trait = true;
|
||||
}
|
||||
}
|
||||
AssocTyConstraintKind::Bound { .. } => {
|
||||
if self.is_assoc_ty_bound_banned {
|
||||
self.err_handler().span_err(constraint.span,
|
||||
"associated type bounds are not allowed within structs, enums, or unions"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.visit_assoc_type_binding(type_binding);
|
||||
self.visit_assoc_ty_constraint(constraint);
|
||||
}
|
||||
|
||||
fn visit_ty_from_generic_args(&mut self, ty: &'a Ty) {
|
||||
// rust-lang/rust#57979: bug in old visit_generic_args called
|
||||
// walk_ty rather than visit_ty, skippping outer `impl Trait`
|
||||
// if it happened to occur at `ty`
|
||||
// rust-lang/rust#57979: bug in old `visit_generic_args` called
|
||||
// `walk_ty` rather than `visit_ty`, skippping outer `impl Trait`
|
||||
// if it happened to occur at `ty`.
|
||||
if let TyKind::ImplTrait(..) = ty.node {
|
||||
self.warning_period_57979_didnt_record_next_impl_trait = true;
|
||||
}
|
||||
|
|
@ -117,10 +138,10 @@ impl<'a> AstValidator<'a> {
|
|||
let only_recorded_since_pull_request_57730 =
|
||||
self.warning_period_57979_didnt_record_next_impl_trait;
|
||||
|
||||
// (this flag is designed to be set to true and then only
|
||||
// (This flag is designed to be set to `true`, and then only
|
||||
// reach the construction point for the outer impl trait once,
|
||||
// so its safe and easiest to unconditionally reset it to
|
||||
// false)
|
||||
// false.)
|
||||
self.warning_period_57979_didnt_record_next_impl_trait = false;
|
||||
|
||||
OuterImplTrait {
|
||||
|
|
@ -128,7 +149,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Mirrors visit::walk_ty, but tracks relevant state
|
||||
// Mirrors `visit::walk_ty`, but tracks relevant state.
|
||||
fn walk_ty(&mut self, t: &'a Ty) {
|
||||
match t.node {
|
||||
TyKind::ImplTrait(..) => {
|
||||
|
|
@ -619,15 +640,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
// Auto traits cannot have generics, super traits nor contain items.
|
||||
if !generics.params.is_empty() {
|
||||
struct_span_err!(self.session, item.span, E0567,
|
||||
"auto traits cannot have generic parameters").emit();
|
||||
"auto traits cannot have generic parameters"
|
||||
).emit();
|
||||
}
|
||||
if !bounds.is_empty() {
|
||||
struct_span_err!(self.session, item.span, E0568,
|
||||
"auto traits cannot have super traits").emit();
|
||||
"auto traits cannot have super traits"
|
||||
).emit();
|
||||
}
|
||||
if !trait_items.is_empty() {
|
||||
struct_span_err!(self.session, item.span, E0380,
|
||||
"auto traits cannot have methods or associated items").emit();
|
||||
"auto traits cannot have methods or associated items"
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
self.no_questions_in_bounds(bounds, "supertraits", true);
|
||||
|
|
@ -699,7 +723,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
visit::walk_foreign_item(self, fi)
|
||||
}
|
||||
|
||||
// Mirrors visit::walk_generic_args, but tracks relevant state
|
||||
// Mirrors `visit::walk_generic_args`, but tracks relevant state.
|
||||
fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
|
||||
match *generic_args {
|
||||
GenericArgs::AngleBracketed(ref data) => {
|
||||
|
|
@ -718,10 +742,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
generic_args.span(),
|
||||
);
|
||||
|
||||
// Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
|
||||
// Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
|
||||
// are allowed to contain nested `impl Trait`.
|
||||
self.with_impl_trait(None, |this| {
|
||||
walk_list!(this, visit_assoc_type_binding_from_generic_args, &data.bindings);
|
||||
walk_list!(this, visit_assoc_ty_constraint_from_generic_args,
|
||||
&data.constraints);
|
||||
});
|
||||
}
|
||||
GenericArgs::Parenthesized(ref data) => {
|
||||
|
|
@ -814,6 +839,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
visit::walk_poly_trait_ref(self, t, m);
|
||||
}
|
||||
|
||||
fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident,
|
||||
_: &'a Generics, _: NodeId, _: Span) {
|
||||
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
|
||||
}
|
||||
|
||||
fn visit_enum_def(&mut self, enum_definition: &'a EnumDef,
|
||||
generics: &'a Generics, item_id: NodeId, _: Span) {
|
||||
self.with_banned_assoc_ty_bound(
|
||||
|this| visit::walk_enum_def(this, enum_definition, generics, item_id))
|
||||
}
|
||||
|
||||
fn visit_mac(&mut self, mac: &Spanned<Mac_>) {
|
||||
// when a new macro kind is added but the author forgets to set it up for expansion
|
||||
// because that's the only part that won't cause a compiler error
|
||||
|
|
@ -837,6 +873,7 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
|
|||
has_global_allocator: false,
|
||||
outer_impl_trait: None,
|
||||
is_impl_trait_banned: false,
|
||||
is_assoc_ty_bound_banned: false,
|
||||
warning_period_57979_didnt_record_next_impl_trait: false,
|
||||
warning_period_57979_impl_trait_in_proj: false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -353,9 +353,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
|||
ast_visit::walk_path_segment(self, path_span, path_segment)
|
||||
}
|
||||
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &'v ast::TypeBinding) {
|
||||
self.record("TypeBinding", Id::None, type_binding);
|
||||
ast_visit::walk_assoc_type_binding(self, type_binding)
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
|
||||
self.record("AssocTyConstraint", Id::None, constraint);
|
||||
ast_visit::walk_assoc_ty_constraint(self, constraint)
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
|
||||
|
|
|
|||
|
|
@ -1040,12 +1040,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
if !self.in_body {
|
||||
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
|
||||
// The traits' privacy in bodies is already checked as a part of trait object types.
|
||||
let (principal, projections) =
|
||||
rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
|
||||
let (principal, bounds) = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
|
||||
if self.visit_trait(*principal.skip_binder()) {
|
||||
return;
|
||||
}
|
||||
for (poly_predicate, _) in projections {
|
||||
for (poly_predicate, _) in bounds.projection_bounds {
|
||||
let tcx = self.tcx;
|
||||
if self.visit(poly_predicate.skip_binder().ty) ||
|
||||
self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
|
||||
|
|
|
|||
|
|
@ -2134,7 +2134,7 @@ impl<'a> Resolver<'a> {
|
|||
record_used_id: Option<NodeId>,
|
||||
path_span: Span)
|
||||
-> Option<LexicalScopeBinding<'a>> {
|
||||
assert!(ns == TypeNS || ns == ValueNS);
|
||||
assert!(ns == TypeNS || ns == ValueNS);
|
||||
if ident.name == kw::Invalid {
|
||||
return Some(LexicalScopeBinding::Res(Res::Err));
|
||||
}
|
||||
|
|
@ -2529,11 +2529,23 @@ impl<'a> Resolver<'a> {
|
|||
debug!("(resolving item) resolving {} ({:?})", name, item.node);
|
||||
|
||||
match item.node {
|
||||
ItemKind::Ty(_, ref generics) |
|
||||
ItemKind::Fn(_, _, ref generics, _) |
|
||||
ItemKind::Existential(_, ref generics) => {
|
||||
self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind),
|
||||
|this| visit::walk_item(this, item));
|
||||
ItemKind::Ty(_, ref generics) => {
|
||||
self.with_current_self_item(item, |this| {
|
||||
this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
|
||||
let item_def_id = this.definitions.local_def_id(item.id);
|
||||
this.with_self_rib(Res::SelfTy(Some(item_def_id), None), |this| {
|
||||
visit::walk_item(this, item)
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Existential(_, ref generics) |
|
||||
ItemKind::Fn(_, _, ref generics, _) => {
|
||||
self.with_generic_param_rib(
|
||||
HasGenericParams(generics, ItemRibKind),
|
||||
|this| visit::walk_item(this, item)
|
||||
);
|
||||
}
|
||||
|
||||
ItemKind::Enum(_, ref generics) |
|
||||
|
|
@ -2967,7 +2979,7 @@ impl<'a> Resolver<'a> {
|
|||
binding_map
|
||||
}
|
||||
|
||||
// check that all of the arms in an or-pattern have exactly the
|
||||
// Checks that all of the arms in an or-pattern have exactly the
|
||||
// same set of bindings, with the same binding modes for each.
|
||||
fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
|
||||
if pats.is_empty() {
|
||||
|
|
@ -2987,7 +2999,7 @@ impl<'a> Resolver<'a> {
|
|||
let map_j = self.binding_mode_map(&q);
|
||||
for (&key, &binding_i) in &map_i {
|
||||
if map_j.is_empty() { // Account for missing bindings when
|
||||
let binding_error = missing_vars // map_j has none.
|
||||
let binding_error = missing_vars // `map_j` has none.
|
||||
.entry(key.name)
|
||||
.or_insert(BindingError {
|
||||
name: key.name,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::hir::def::{CtorOf, Res, DefKind};
|
|||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::HirVec;
|
||||
use crate::lint;
|
||||
use crate::middle::lang_items::SizedTraitLangItem;
|
||||
use crate::middle::resolve_lifetime as rl;
|
||||
use crate::namespace::Namespace;
|
||||
use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
|
|
@ -47,14 +48,14 @@ pub trait AstConv<'gcx, 'tcx> {
|
|||
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
|
||||
-> &'tcx ty::GenericPredicates<'tcx>;
|
||||
|
||||
/// What lifetime should we use when a lifetime is omitted (and not elided)?
|
||||
/// Returns the lifetime to use when a lifetime is omitted (and not elided).
|
||||
fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
|
||||
-> Option<ty::Region<'tcx>>;
|
||||
|
||||
/// What type should we use when a type is omitted?
|
||||
/// Returns the type to use when a type is omitted.
|
||||
fn ty_infer(&self, span: Span) -> Ty<'tcx>;
|
||||
|
||||
/// Same as ty_infer, but with a known type parameter definition.
|
||||
/// Same as `ty_infer`, but with a known type parameter definition.
|
||||
fn ty_infer_for_def(&self,
|
||||
_def: &ty::GenericParamDef,
|
||||
span: Span) -> Ty<'tcx> {
|
||||
|
|
@ -86,12 +87,22 @@ pub trait AstConv<'gcx, 'tcx> {
|
|||
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
|
||||
}
|
||||
|
||||
pub enum SizedByDefault {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
struct ConvertedBinding<'tcx> {
|
||||
item_name: ast::Ident,
|
||||
ty: Ty<'tcx>,
|
||||
kind: ConvertedBindingKind<'tcx>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
enum ConvertedBindingKind<'tcx> {
|
||||
Equality(Ty<'tcx>),
|
||||
Constraint(P<[hir::GenericBound]>),
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum GenericArgPosition {
|
||||
Type,
|
||||
|
|
@ -376,8 +387,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
}
|
||||
err.emit();
|
||||
|
||||
(provided > required, // `suppress_error`
|
||||
potential_assoc_types)
|
||||
(
|
||||
provided > required, // `suppress_error`
|
||||
potential_assoc_types,
|
||||
)
|
||||
};
|
||||
|
||||
if reported_late_bound_region_err.is_none()
|
||||
|
|
@ -556,14 +569,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
}
|
||||
|
||||
/// Given the type/lifetime/const arguments provided to some path (along with
|
||||
/// an implicit `Self`, if this is a trait reference) returns the complete
|
||||
/// an implicit `Self`, if this is a trait reference), returns the complete
|
||||
/// set of substitutions. This may involve applying defaulted type parameters.
|
||||
/// Also returns back constriants on associated types.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// T: std::ops::Index<usize, Output = u32>
|
||||
/// ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4
|
||||
/// ```
|
||||
///
|
||||
/// 1. The `self_ty` here would refer to the type `T`.
|
||||
/// 2. The path in question is the path to the trait `std::ops::Index`,
|
||||
/// which will have been resolved to a `def_id`
|
||||
/// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
|
||||
/// parameters are returned in the `SubstsRef`, the associated type bindings like
|
||||
/// `Output = u32` are returned in the `Vec<ConvertedBinding...>` result.
|
||||
///
|
||||
/// Note that the type listing given here is *exactly* what the user provided.
|
||||
fn create_substs_for_ast_path(&self,
|
||||
fn create_substs_for_ast_path<'a>(&self,
|
||||
span: Span,
|
||||
def_id: DefId,
|
||||
generic_args: &hir::GenericArgs,
|
||||
generic_args: &'a hir::GenericArgs,
|
||||
infer_types: bool,
|
||||
self_ty: Option<Ty<'tcx>>)
|
||||
-> (SubstsRef<'tcx>, Vec<ConvertedBinding<'tcx>>, Option<Vec<Span>>)
|
||||
|
|
@ -686,13 +714,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
},
|
||||
);
|
||||
|
||||
let assoc_bindings = generic_args.bindings.iter().map(|binding| {
|
||||
ConvertedBinding {
|
||||
item_name: binding.ident,
|
||||
ty: self.ast_ty_to_ty(&binding.ty),
|
||||
span: binding.span,
|
||||
}
|
||||
}).collect();
|
||||
// Convert associated-type bindings or constraints into a separate vector.
|
||||
// Example: Given this:
|
||||
//
|
||||
// T: Iterator<Item = u32>
|
||||
//
|
||||
// The `T` is passed in as a self-type; the `Item = u32` is
|
||||
// not a "type parameter" of the `Iterator` trait, but rather
|
||||
// a restriction on `<T as Iterator>::Item`, so it is passed
|
||||
// back separately.
|
||||
let assoc_bindings = generic_args.bindings.iter()
|
||||
.map(|binding| {
|
||||
let kind = match binding.kind {
|
||||
hir::TypeBindingKind::Equality { ref ty } =>
|
||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)),
|
||||
hir::TypeBindingKind::Constraint { ref bounds } =>
|
||||
ConvertedBindingKind::Constraint(bounds.clone()),
|
||||
};
|
||||
ConvertedBinding {
|
||||
item_name: binding.ident,
|
||||
kind,
|
||||
span: binding.span,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
debug!("create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
|
||||
generic_params, self_ty, substs);
|
||||
|
|
@ -708,8 +753,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
/// are disallowed. Otherwise, they are pushed onto the vector given.
|
||||
pub fn instantiate_mono_trait_ref(&self,
|
||||
trait_ref: &hir::TraitRef,
|
||||
self_ty: Ty<'tcx>)
|
||||
-> ty::TraitRef<'tcx>
|
||||
self_ty: Ty<'tcx>
|
||||
) -> ty::TraitRef<'tcx>
|
||||
{
|
||||
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
|
||||
|
||||
|
|
@ -723,9 +768,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
pub(super) fn instantiate_poly_trait_ref_inner(&self,
|
||||
trait_ref: &hir::TraitRef,
|
||||
self_ty: Ty<'tcx>,
|
||||
poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
|
||||
speculative: bool)
|
||||
-> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
|
||||
{
|
||||
let trait_def_id = trait_ref.trait_def_id();
|
||||
|
||||
|
|
@ -742,36 +787,59 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
|
||||
|
||||
let mut dup_bindings = FxHashMap::default();
|
||||
poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
|
||||
// specify type to assert that error was already reported in Err case:
|
||||
let predicate: Result<_, ErrorReported> =
|
||||
self.ast_type_binding_to_poly_projection_predicate(
|
||||
trait_ref.hir_ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
|
||||
// okay to ignore Err because of ErrorReported (see above)
|
||||
Some((predicate.ok()?, binding.span))
|
||||
}));
|
||||
for binding in &assoc_bindings {
|
||||
// Specify type to assert that error was already reported in `Err` case.
|
||||
let _: Result<_, ErrorReported> =
|
||||
self.add_predicates_for_ast_type_binding(
|
||||
trait_ref.hir_ref_id,
|
||||
poly_trait_ref,
|
||||
binding,
|
||||
bounds,
|
||||
speculative,
|
||||
&mut dup_bindings
|
||||
);
|
||||
// Okay to ignore `Err` because of `ErrorReported` (see above).
|
||||
}
|
||||
|
||||
debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
|
||||
trait_ref, poly_projections, poly_trait_ref);
|
||||
debug!("instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}",
|
||||
trait_ref, bounds, poly_trait_ref);
|
||||
(poly_trait_ref, potential_assoc_types)
|
||||
}
|
||||
|
||||
/// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
|
||||
/// a full trait reference. The resulting trait reference is returned. This may also generate
|
||||
/// auxiliary bounds, which are added to `bounds`.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// poly_trait_ref = Iterator<Item = u32>
|
||||
/// self_ty = Foo
|
||||
/// ```
|
||||
///
|
||||
/// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
|
||||
///
|
||||
/// **A note on binders:** against our usual convention, there is an implied bounder around
|
||||
/// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
|
||||
/// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
|
||||
/// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
|
||||
/// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
|
||||
/// however.
|
||||
pub fn instantiate_poly_trait_ref(&self,
|
||||
poly_trait_ref: &hir::PolyTraitRef,
|
||||
self_ty: Ty<'tcx>,
|
||||
poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>)
|
||||
-> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
|
||||
bounds: &mut Bounds<'tcx>
|
||||
) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
|
||||
{
|
||||
self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty,
|
||||
poly_projections, false)
|
||||
self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, bounds, false)
|
||||
}
|
||||
|
||||
fn ast_path_to_mono_trait_ref(&self,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_segment: &hir::PathSegment)
|
||||
-> ty::TraitRef<'tcx>
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_segment: &hir::PathSegment
|
||||
) -> ty::TraitRef<'tcx>
|
||||
{
|
||||
let (substs, assoc_bindings, _) =
|
||||
self.create_substs_for_ast_trait_ref(span,
|
||||
|
|
@ -828,15 +896,156 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
})
|
||||
}
|
||||
|
||||
fn ast_type_binding_to_poly_projection_predicate(
|
||||
// Returns `true` if a bounds list includes `?Sized`.
|
||||
pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound], span: Span) -> bool {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// Try to find an unbound in bounds.
|
||||
let mut unbound = None;
|
||||
for ab in ast_bounds {
|
||||
if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
|
||||
if unbound.is_none() {
|
||||
unbound = Some(ptr.trait_ref.clone());
|
||||
} else {
|
||||
span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0203,
|
||||
"type parameter has more than one relaxed default \
|
||||
bound, only one is supported"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let kind_id = tcx.lang_items().require(SizedTraitLangItem);
|
||||
match unbound {
|
||||
Some(ref tpb) => {
|
||||
// FIXME(#8559) currently requires the unbound to be built-in.
|
||||
if let Ok(kind_id) = kind_id {
|
||||
if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
|
||||
tcx.sess.span_warn(
|
||||
span,
|
||||
"default bound relaxed for a type parameter, but \
|
||||
this does nothing because the given bound is not \
|
||||
a default. Only `?Sized` is supported",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ if kind_id.is_ok() => {
|
||||
return false;
|
||||
}
|
||||
// No lang item for `Sized`, so we can't add it as a bound.
|
||||
None => {}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// This helper takes a *converted* parameter type (`param_ty`)
|
||||
/// and an *unconverted* list of bounds:
|
||||
///
|
||||
/// ```
|
||||
/// fn foo<T: Debug>
|
||||
/// ^ ^^^^^ `ast_bounds` parameter, in HIR form
|
||||
/// |
|
||||
/// `param_ty`, in ty form
|
||||
/// ```
|
||||
///
|
||||
/// It adds these `ast_bounds` into the `bounds` structure.
|
||||
///
|
||||
/// **A note on binders:** there is an implied binder around
|
||||
/// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
|
||||
/// for more details.
|
||||
fn add_bounds(&self,
|
||||
param_ty: Ty<'tcx>,
|
||||
ast_bounds: &[hir::GenericBound],
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
) {
|
||||
let mut trait_bounds = Vec::new();
|
||||
let mut region_bounds = Vec::new();
|
||||
|
||||
for ast_bound in ast_bounds {
|
||||
match *ast_bound {
|
||||
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) =>
|
||||
trait_bounds.push(b),
|
||||
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
|
||||
hir::GenericBound::Outlives(ref l) =>
|
||||
region_bounds.push(l),
|
||||
}
|
||||
}
|
||||
|
||||
for bound in trait_bounds {
|
||||
let (poly_trait_ref, _) = self.instantiate_poly_trait_ref(
|
||||
bound,
|
||||
param_ty,
|
||||
bounds,
|
||||
);
|
||||
bounds.trait_bounds.push((poly_trait_ref, bound.span))
|
||||
}
|
||||
|
||||
bounds.region_bounds.extend(region_bounds
|
||||
.into_iter()
|
||||
.map(|r| (self.ast_region_to_region(r, None), r.span))
|
||||
);
|
||||
}
|
||||
|
||||
/// Translates a list of bounds from the HIR into the `Bounds` data structure.
|
||||
/// The self-type for the bounds is given by `param_ty`.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```
|
||||
/// fn foo<T: Bar + Baz>() { }
|
||||
/// ^ ^^^^^^^^^ ast_bounds
|
||||
/// param_ty
|
||||
/// ```
|
||||
///
|
||||
/// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
|
||||
/// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
|
||||
/// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
|
||||
///
|
||||
/// `span` should be the declaration size of the parameter.
|
||||
pub fn compute_bounds(&self,
|
||||
param_ty: Ty<'tcx>,
|
||||
ast_bounds: &[hir::GenericBound],
|
||||
sized_by_default: SizedByDefault,
|
||||
span: Span,
|
||||
) -> Bounds<'tcx> {
|
||||
let mut bounds = Bounds::default();
|
||||
|
||||
self.add_bounds(param_ty, ast_bounds, &mut bounds);
|
||||
bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
|
||||
|
||||
bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
|
||||
if !self.is_unsized(ast_bounds, span) {
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
bounds
|
||||
}
|
||||
|
||||
/// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
|
||||
/// onto `bounds`.
|
||||
///
|
||||
/// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
|
||||
/// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
|
||||
/// the binder (e.g., `&'a u32`) and hence may reference bound regions.
|
||||
fn add_predicates_for_ast_type_binding(
|
||||
&self,
|
||||
hir_ref_id: hir::HirId,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
binding: &ConvertedBinding<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
dup_bindings: &mut FxHashMap<DefId, Span>)
|
||||
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
|
||||
{
|
||||
dup_bindings: &mut FxHashMap<DefId, Span>,
|
||||
) -> Result<(), ErrorReported> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
if !speculative {
|
||||
|
|
@ -851,40 +1060,43 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
// trait SubTrait: SuperTrait<int> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B : SubTrait<T=foo> ...
|
||||
// ... B: SubTrait<T = foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref. These are not wellformed.
|
||||
// declared in the trait-ref. These are not well-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
|
||||
let late_bound_in_ty =
|
||||
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(binding.ty));
|
||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||
let br_name = match *br {
|
||||
ty::BrNamed(_, name) => name,
|
||||
_ => {
|
||||
span_bug!(
|
||||
binding.span,
|
||||
"anonymous bound region {:?} in binding but not trait ref",
|
||||
br);
|
||||
}
|
||||
};
|
||||
struct_span_err!(tcx.sess,
|
||||
if let ConvertedBindingKind::Equality(ty) = binding.kind {
|
||||
let late_bound_in_trait_ref =
|
||||
tcx.collect_constrained_late_bound_regions(&trait_ref);
|
||||
let late_bound_in_ty =
|
||||
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
|
||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||
let br_name = match *br {
|
||||
ty::BrNamed(_, name) => name,
|
||||
_ => {
|
||||
span_bug!(
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references lifetime `{}`, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name, br_name)
|
||||
.emit();
|
||||
"anonymous bound region {:?} in binding but not trait ref",
|
||||
br);
|
||||
}
|
||||
};
|
||||
struct_span_err!(tcx.sess,
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references lifetime `{}`, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name, br_name)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -929,16 +1141,39 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
.or_insert(binding.span);
|
||||
}
|
||||
|
||||
Ok(candidate.map_bound(|trait_ref| {
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
binding.item_name,
|
||||
),
|
||||
ty: binding.ty,
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(ref ty) => {
|
||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||
// the "projection predicate" for:
|
||||
//
|
||||
// `<T as Iterator>::Item = u32`
|
||||
bounds.projection_bounds.push((candidate.map_bound(|trait_ref| {
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
binding.item_name,
|
||||
),
|
||||
ty,
|
||||
}
|
||||
}), binding.span));
|
||||
}
|
||||
}))
|
||||
ConvertedBindingKind::Constraint(ref ast_bounds) => {
|
||||
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
|
||||
//
|
||||
// `<T as Iterator>::Item: Debug`
|
||||
//
|
||||
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
|
||||
// parameter to have a skipped binder.
|
||||
let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
|
||||
self.add_bounds(
|
||||
param_ty,
|
||||
ast_bounds,
|
||||
bounds,
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ast_path_to_ty(&self,
|
||||
|
|
@ -972,7 +1207,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
let mut projection_bounds = Vec::new();
|
||||
let mut bounds = Bounds::default();
|
||||
let mut potential_assoc_types = Vec::new();
|
||||
let dummy_self = self.tcx().types.trait_object_dummy_self;
|
||||
// FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is
|
||||
|
|
@ -984,7 +1219,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref(
|
||||
trait_bound,
|
||||
dummy_self,
|
||||
&mut projection_bounds
|
||||
&mut bounds,
|
||||
);
|
||||
potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
|
||||
(trait_ref, trait_bound.span)
|
||||
|
|
@ -1072,14 +1307,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
// which is uglier but works. See the discussion in #56288 for alternatives.
|
||||
if !references_self {
|
||||
// Include projections defined on supertraits.
|
||||
projection_bounds.push((pred, DUMMY_SP))
|
||||
bounds.projection_bounds.push((pred, DUMMY_SP))
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
for (projection_bound, _) in &projection_bounds {
|
||||
for (projection_bound, _) in &bounds.projection_bounds {
|
||||
associated_types.remove(&projection_bound.projection_def_id());
|
||||
}
|
||||
|
||||
|
|
@ -1159,7 +1394,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
let existential_trait_refs = regular_traits.iter().map(|i| {
|
||||
i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref))
|
||||
});
|
||||
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
|
||||
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
|
||||
bound.map_bound(|b| {
|
||||
let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
|
||||
ty::ExistentialProjection {
|
||||
|
|
@ -1716,7 +1951,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
let span = path.span;
|
||||
match path.res {
|
||||
Res::Def(DefKind::Existential, did) => {
|
||||
// Check for desugared impl trait.
|
||||
// Check for desugared `impl Trait`.
|
||||
assert!(ty::is_impl_trait_defn(tcx, did).is_none());
|
||||
let item_segment = path.segments.split_last().unwrap();
|
||||
self.prohibit_generics(item_segment.1);
|
||||
|
|
@ -1767,19 +2002,19 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
&tcx.hir().local_def_id_from_hir_id(hir_id)];
|
||||
tcx.mk_ty_param(index, tcx.hir().name_by_hir_id(hir_id).as_interned_str())
|
||||
}
|
||||
Res::SelfTy(Some(_), None) => {
|
||||
// `Self` in trait or type alias.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
self.prohibit_generics(&path.segments);
|
||||
tcx.mk_self_type()
|
||||
}
|
||||
Res::SelfTy(_, Some(def_id)) => {
|
||||
// `Self` in impl (we know the concrete type).
|
||||
assert_eq!(opt_self_ty, None);
|
||||
self.prohibit_generics(&path.segments);
|
||||
// Try to evaluate any array length constants
|
||||
// Try to evaluate any array length constants.
|
||||
self.normalize_ty(span, tcx.at(span).type_of(def_id))
|
||||
}
|
||||
Res::SelfTy(Some(_), None) => {
|
||||
// `Self` in trait.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
self.prohibit_generics(&path.segments);
|
||||
tcx.mk_self_type()
|
||||
}
|
||||
Res::Def(DefKind::AssocTy, def_id) => {
|
||||
debug_assert!(path.segments.len() >= 2);
|
||||
self.prohibit_generics(&path.segments[..path.segments.len() - 2]);
|
||||
|
|
@ -1829,7 +2064,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
}
|
||||
hir::TyKind::Rptr(ref region, ref mt) => {
|
||||
let r = self.ast_region_to_region(region, None);
|
||||
debug!("Ref r={:?}", r);
|
||||
debug!("ast_ty_to_ty: r={:?}", r);
|
||||
let t = self.ast_ty_to_ty(&mt.ty);
|
||||
tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
|
||||
}
|
||||
|
|
@ -1856,7 +2091,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
hir::TyKind::Def(item_id, ref lifetimes) => {
|
||||
let did = tcx.hir().local_def_id_from_hir_id(item_id.id);
|
||||
self.impl_trait_ty_to_ty(did, lifetimes)
|
||||
},
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
|
||||
debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
|
||||
let ty = self.ast_ty_to_ty(qself);
|
||||
|
|
@ -1889,9 +2124,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
// handled specially and will not descend into this routine.
|
||||
self.ty_infer(ast_ty.span)
|
||||
}
|
||||
hir::TyKind::Err => {
|
||||
tcx.types.err
|
||||
}
|
||||
hir::TyKind::CVarArgs(lt) => {
|
||||
let va_list_did = match tcx.lang_items().va_list() {
|
||||
Some(did) => did,
|
||||
|
|
@ -1901,8 +2133,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
let region = self.ast_region_to_region(<, None);
|
||||
tcx.type_of(va_list_did).subst(tcx, &[region.into()])
|
||||
}
|
||||
hir::TyKind::Err => {
|
||||
tcx.types.err
|
||||
}
|
||||
};
|
||||
|
||||
debug!("ast_ty_to_ty: result_ty={:?}", result_ty);
|
||||
|
||||
self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
|
||||
result_ty
|
||||
}
|
||||
|
|
@ -1979,7 +2216,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
_ => bug!()
|
||||
}
|
||||
} else {
|
||||
// Replace all parent lifetimes with 'static.
|
||||
// Replace all parent lifetimes with `'static`.
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
tcx.lifetimes.re_static.into()
|
||||
|
|
@ -1988,7 +2225,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
});
|
||||
debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
|
||||
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
|
||||
|
||||
let ty = tcx.mk_opaque(def_id, substs);
|
||||
debug!("impl_trait_ty_to_ty: {}", ty);
|
||||
|
|
@ -2117,17 +2354,52 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
|
||||
// A helper struct for conveniently grouping a set of bounds which we pass to
|
||||
// and return from functions in multiple places.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
/// Collects together a list of bounds that are applied to some type,
|
||||
/// after they've been converted into `ty` form (from the HIR
|
||||
/// representations). These lists of bounds occur in many places in
|
||||
/// Rust's syntax:
|
||||
///
|
||||
/// ```
|
||||
/// trait Foo: Bar + Baz { }
|
||||
/// ^^^^^^^^^ supertrait list bounding the `Self` type parameter
|
||||
///
|
||||
/// fn foo<T: Bar + Baz>() { }
|
||||
/// ^^^^^^^^^ bounding the type parameter `T`
|
||||
///
|
||||
/// impl dyn Bar + Baz
|
||||
/// ^^^^^^^^^ bounding the forgotten dynamic type
|
||||
/// ```
|
||||
///
|
||||
/// Our representation is a bit mixed here -- in some cases, we
|
||||
/// include the self type (e.g., `trait_bounds`) but in others we do
|
||||
#[derive(Default, PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Bounds<'tcx> {
|
||||
/// A list of region bounds on the (implicit) self type. So if you
|
||||
/// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
|
||||
/// the `T` is not explicitly included).
|
||||
pub region_bounds: Vec<(ty::Region<'tcx>, Span)>,
|
||||
pub implicitly_sized: Option<Span>,
|
||||
|
||||
/// A list of trait bounds. So if you had `T: Debug` this would be
|
||||
/// `T: Debug`. Note that the self-type is explicit here.
|
||||
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
|
||||
|
||||
/// A list of projection equality bounds. So if you had `T:
|
||||
/// Iterator<Item = u32>` this would include `<T as
|
||||
/// Iterator>::Item => u32`. Note that the self-type is explicit
|
||||
/// here.
|
||||
pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
|
||||
|
||||
/// `Some` if there is *no* `?Sized` predicate. The `span`
|
||||
/// is the location in the source of the `T` declaration which can
|
||||
/// be cited as the source of the `T: Sized` requirement.
|
||||
pub implicitly_sized: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
|
||||
/// Converts a bounds list into a flat set of predicates (like
|
||||
/// where-clauses). Because some of our bounds listings (e.g.,
|
||||
/// regions) don't include the self-type, you must supply the
|
||||
/// self-type here (the `param_ty` parameter).
|
||||
pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
|
||||
-> Vec<(ty::Predicate<'tcx>, Span)>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
// here, we would coerce from `!` to `?T`.
|
||||
let b = self.shallow_resolve(b);
|
||||
return if self.shallow_resolve(b).is_ty_var() {
|
||||
// micro-optimization: no need for this if `b` is
|
||||
// Micro-optimization: no need for this if `b` is
|
||||
// already resolved in some way.
|
||||
let diverging_ty = self.next_diverging_ty_var(
|
||||
TypeVariableOrigin {
|
||||
|
|
|
|||
|
|
@ -523,10 +523,10 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
/// eventually).
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
// Number of errors that had been reported when we started
|
||||
// checking this function. On exit, if we find that *more* errors
|
||||
// have been reported, we will skip regionck and other work that
|
||||
// expects the types within the function to be consistent.
|
||||
/// Number of errors that had been reported when we started
|
||||
/// checking this function. On exit, if we find that *more* errors
|
||||
/// have been reported, we will skip regionck and other work that
|
||||
/// expects the types within the function to be consistent.
|
||||
err_count_on_creation: usize,
|
||||
|
||||
ret_coercion: Option<RefCell<DynamicCoerceMany<'gcx, 'tcx>>>,
|
||||
|
|
|
|||
|
|
@ -991,8 +991,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Guarantees that any lifetimes which appear in the type of the node `id` (after applying
|
||||
/// adjustments) are valid for at least `minimum_lifetime`
|
||||
/// Guarantees that any lifetimes that appear in the type of the node `id` (after applying
|
||||
/// adjustments) are valid for at least `minimum_lifetime`.
|
||||
fn type_of_node_must_outlive(
|
||||
&mut self,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@ use rustc::hir::itemlikevisit::ParItemLikeVisitor;
|
|||
use rustc::hir;
|
||||
|
||||
/// Helper type of a temporary returned by `.for_item(...)`.
|
||||
/// Necessary because we can't write the following bound:
|
||||
/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)`.
|
||||
/// This is necessary because we can't write the following bound:
|
||||
///
|
||||
/// ```rust
|
||||
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)
|
||||
/// ```
|
||||
struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
|
||||
id: hir::HirId,
|
||||
|
|
@ -42,7 +45,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
|
|||
if !inh.tcx.features().trivial_bounds {
|
||||
// As predicates are cached rather than obligations, this
|
||||
// needsto be called first so that they are checked with an
|
||||
// empty param_env.
|
||||
// empty `param_env`.
|
||||
check_false_global_bounds(&fcx, span, id);
|
||||
}
|
||||
let wf_tys = f(&fcx, fcx.tcx.global_tcx());
|
||||
|
|
@ -56,7 +59,9 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
|
|||
/// well-formed, meaning that they do not require any constraints not declared in the struct
|
||||
/// definition itself. For example, this definition would be illegal:
|
||||
///
|
||||
/// struct Ref<'a, T> { x: &'a T }
|
||||
/// ```rust
|
||||
/// struct Ref<'a, T> { x: &'a T }
|
||||
/// ```
|
||||
///
|
||||
/// because the type did not declare that `T:'a`.
|
||||
///
|
||||
|
|
@ -75,7 +80,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
|
|||
// Right now we check that every default trait implementation
|
||||
// has an implementation of itself. Basically, a case like:
|
||||
//
|
||||
// `impl Trait for T {}`
|
||||
// impl Trait for T {}
|
||||
//
|
||||
// has a requirement of `T: Trait` which was required for default
|
||||
// method implementations. Although this could be improved now that
|
||||
|
|
@ -85,7 +90,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
|
|||
// Since there's such a requirement, we need to check *just* positive
|
||||
// implementations, otherwise things like:
|
||||
//
|
||||
// impl !Send for T {}
|
||||
// impl !Send for T {}
|
||||
//
|
||||
// won't be allowed unless there's an *explicit* implementation of `Send`
|
||||
// for `T`
|
||||
|
|
@ -98,7 +103,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
|
|||
if polarity == hir::ImplPolarity::Positive {
|
||||
check_impl(tcx, item, self_ty, trait_ref);
|
||||
} else {
|
||||
// FIXME(#27579) what amount of WF checking do we need for neg impls?
|
||||
// FIXME(#27579): what amount of WF checking do we need for neg impls?
|
||||
if trait_ref.is_some() && !is_auto {
|
||||
span_err!(tcx.sess, item.span, E0192,
|
||||
"negative impls are only allowed for \
|
||||
|
|
@ -302,7 +307,8 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
check_where_clauses(tcx, fcx, item.span, def_id, None);
|
||||
|
||||
vec![] // no implied bounds in a struct def'n
|
||||
// No implied bounds in a struct definition.
|
||||
vec![]
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -369,7 +375,8 @@ fn check_item_type<'a, 'tcx>(
|
|||
);
|
||||
}
|
||||
|
||||
vec![] // no implied bounds in a const etc
|
||||
// No implied bounds in a const, etc.
|
||||
vec![]
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -421,6 +428,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
|
|||
def_id: DefId,
|
||||
return_ty: Option<Ty<'tcx>>,
|
||||
) {
|
||||
debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty);
|
||||
|
||||
let predicates = fcx.tcx.predicates_of(def_id);
|
||||
let generics = tcx.generics_of(def_id);
|
||||
|
||||
|
|
@ -434,15 +443,17 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
|
|||
};
|
||||
|
||||
// Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
|
||||
// For example this forbids the declaration:
|
||||
// struct Foo<T = Vec<[u32]>> { .. }
|
||||
// Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
|
||||
// For example, this forbids the declaration:
|
||||
//
|
||||
// struct Foo<T = Vec<[u32]>> { .. }
|
||||
//
|
||||
// Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
|
||||
for param in &generics.params {
|
||||
if let GenericParamDefKind::Type { .. } = param.kind {
|
||||
if is_our_default(¶m) {
|
||||
let ty = fcx.tcx.type_of(param.def_id);
|
||||
// ignore dependent defaults -- that is, where the default of one type
|
||||
// parameter includes another (e.g., <T, U = T>). In those cases, we can't
|
||||
// Ignore dependent defaults -- that is, where the default of one type
|
||||
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
|
||||
// be sure if it will error or not as user might always specify the other.
|
||||
if !ty.needs_subst() {
|
||||
fcx.register_wf_obligation(ty, fcx.tcx.def_span(param.def_id),
|
||||
|
|
@ -468,16 +479,16 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
|
|||
}
|
||||
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
// If the param has a default,
|
||||
// If the param has a default, ...
|
||||
if is_our_default(param) {
|
||||
let default_ty = fcx.tcx.type_of(param.def_id);
|
||||
// and it's not a dependent default
|
||||
// ... and it's not a dependent default, ...
|
||||
if !default_ty.needs_subst() {
|
||||
// then substitute with the default.
|
||||
// ... then substitute it with the default.
|
||||
return default_ty.into();
|
||||
}
|
||||
}
|
||||
// Mark unwanted params as err.
|
||||
// Mark unwanted params as error.
|
||||
fcx.tcx.types.err.into()
|
||||
}
|
||||
|
||||
|
|
@ -525,7 +536,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
|
|||
Some(substituted_pred)
|
||||
}
|
||||
}).map(|pred| {
|
||||
// convert each of those into an obligation. So if you have
|
||||
// Convert each of those into an obligation. So if you have
|
||||
// something like `struct Foo<T: Copy = String>`, we would
|
||||
// take that predicate `T: Copy`, substitute to `String: Copy`
|
||||
// (actually that happens in the previous `flat_map` call),
|
||||
|
|
@ -595,14 +606,13 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
|||
/// ```rust
|
||||
/// existential type Foo<A, B>;
|
||||
///
|
||||
/// // ok -- `Foo` is applied to two distinct, generic types.
|
||||
/// // Okay -- `Foo` is applied to two distinct, generic types.
|
||||
/// fn a<T, U>() -> Foo<T, U> { .. }
|
||||
///
|
||||
/// // not ok -- `Foo` is applied to `T` twice.
|
||||
/// // Not okay -- `Foo` is applied to `T` twice.
|
||||
/// fn b<T>() -> Foo<T, T> { .. }
|
||||
///
|
||||
///
|
||||
/// // not ok -- `Foo` is applied to a non-generic type.
|
||||
/// // Not okay -- `Foo` is applied to a non-generic type.
|
||||
/// fn b<T>() -> Foo<T, u32> { .. }
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -613,7 +623,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
|
|||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Vec<ty::Predicate<'tcx>> {
|
||||
trace!("check_existential_types: {:?}", ty);
|
||||
trace!("check_existential_types(ty={:?})", ty);
|
||||
let mut substituted_predicates = Vec::new();
|
||||
ty.fold_with(&mut ty::fold::BottomUpFolder {
|
||||
tcx: fcx.tcx,
|
||||
|
|
@ -621,17 +631,17 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
|
|||
if let ty::Opaque(def_id, substs) = ty.sty {
|
||||
trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs);
|
||||
let generics = tcx.generics_of(def_id);
|
||||
// only check named existential types defined in this crate
|
||||
// Only check named existential types defined in this crate.
|
||||
if generics.parent.is_none() && def_id.is_local() {
|
||||
let opaque_hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
if may_define_existential_type(tcx, fn_def_id, opaque_hir_id) {
|
||||
trace!("check_existential_types may define. Generics: {:#?}", generics);
|
||||
trace!("check_existential_types: may define, generics={:#?}", generics);
|
||||
let mut seen: FxHashMap<_, Vec<_>> = FxHashMap::default();
|
||||
for (subst, param) in substs.iter().zip(&generics.params) {
|
||||
match subst.unpack() {
|
||||
ty::subst::UnpackedKind::Type(ty) => match ty.sty {
|
||||
ty::Param(..) => {}
|
||||
// prevent `fn foo() -> Foo<u32>` from being defining
|
||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||
_ => {
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
|
|
@ -713,20 +723,19 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
|
|||
}
|
||||
} // if may_define_existential_type
|
||||
|
||||
// now register the bounds on the parameters of the existential type
|
||||
// so the parameters given by the function need to fulfill them
|
||||
// ```rust
|
||||
// existential type Foo<T: Bar>: 'static;
|
||||
// fn foo<U>() -> Foo<U> { .. *}
|
||||
// ```
|
||||
// Now register the bounds on the parameters of the existential type
|
||||
// so the parameters given by the function need to fulfill them.
|
||||
//
|
||||
// existential type Foo<T: Bar>: 'static;
|
||||
// fn foo<U>() -> Foo<U> { .. *}
|
||||
//
|
||||
// becomes
|
||||
// ```rust
|
||||
// existential type Foo<T: Bar>: 'static;
|
||||
// fn foo<U: Bar>() -> Foo<U> { .. *}
|
||||
// ```
|
||||
//
|
||||
// existential type Foo<T: Bar>: 'static;
|
||||
// fn foo<U: Bar>() -> Foo<U> { .. *}
|
||||
let predicates = tcx.predicates_of(def_id);
|
||||
trace!(
|
||||
"check_existential_types may define. adding predicates: {:#?}",
|
||||
"check_existential_types: may define, predicates={:#?}",
|
||||
predicates,
|
||||
);
|
||||
for &(pred, _) in predicates.predicates.iter() {
|
||||
|
|
@ -751,7 +760,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
|||
method: &ty::AssocItem,
|
||||
self_ty: Ty<'tcx>)
|
||||
{
|
||||
// check that the method has a valid receiver type, given the type `Self`
|
||||
// Check that the method has a valid receiver type, given the type `Self`.
|
||||
debug!("check_method_receiver({:?}, self_ty={:?})",
|
||||
method, self_ty);
|
||||
|
||||
|
|
@ -783,7 +792,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
|||
|
||||
if fcx.tcx.features().arbitrary_self_types {
|
||||
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
|
||||
// report error, arbitrary_self_types was enabled
|
||||
// Report error; `arbitrary_self_types` was enabled.
|
||||
fcx.tcx.sess.diagnostic().mut_span_err(
|
||||
span, &format!("invalid method receiver type: {:?}", receiver_ty)
|
||||
).note("type of `self` must be `Self` or a type that dereferences to it")
|
||||
|
|
@ -794,7 +803,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
|||
} else {
|
||||
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) {
|
||||
if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
|
||||
// report error, would have worked with arbitrary_self_types
|
||||
// Report error; would have worked with `arbitrary_self_types`.
|
||||
feature_gate::feature_err(
|
||||
&fcx.tcx.sess.parse_sess,
|
||||
sym::arbitrary_self_types,
|
||||
|
|
@ -808,7 +817,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
|||
).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
|
||||
.emit();
|
||||
} else {
|
||||
// report error, would not have worked with arbitrary_self_types
|
||||
// Report error; would not have worked with `arbitrary_self_types`.
|
||||
fcx.tcx.sess.diagnostic().mut_span_err(
|
||||
span, &format!("invalid method receiver type: {:?}", receiver_ty)
|
||||
).note("type must be `Self` or a type that dereferences to it")
|
||||
|
|
@ -820,10 +829,11 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
/// returns true if `receiver_ty` would be considered a valid receiver type for `self_ty`. If
|
||||
/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
|
||||
/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
|
||||
/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
|
||||
/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref<Target=self_ty>`.
|
||||
/// strict: `receiver_ty` must implement `Receiver` and directly implement
|
||||
/// `Deref<Target = self_ty>`.
|
||||
///
|
||||
/// N.B., there are cases this function returns `true` but causes an error to be emitted,
|
||||
/// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
|
||||
|
|
@ -839,7 +849,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
|
|||
|
||||
let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
|
||||
|
||||
// `self: Self` is always valid
|
||||
// `self: Self` is always valid.
|
||||
if can_eq_self(receiver_ty) {
|
||||
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) {
|
||||
err.emit();
|
||||
|
|
@ -849,15 +859,15 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
|
|||
|
||||
let mut autoderef = fcx.autoderef(span, receiver_ty);
|
||||
|
||||
// the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`
|
||||
// The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
|
||||
if arbitrary_self_types_enabled {
|
||||
autoderef = autoderef.include_raw_pointers();
|
||||
}
|
||||
|
||||
// the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it.
|
||||
// The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
|
||||
autoderef.next();
|
||||
|
||||
// keep dereferencing `receiver_ty` until we get to `self_ty`
|
||||
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
|
||||
loop {
|
||||
if let Some((potential_self_ty, _)) = autoderef.next() {
|
||||
debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`",
|
||||
|
|
@ -882,14 +892,14 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
|
|||
return receiver_ty.references_error();
|
||||
}
|
||||
|
||||
// without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
|
||||
// `self_ty`. Enforce this by only doing one iteration of the loop
|
||||
// Without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
|
||||
// `self_ty`. Enforce this by only doing one iteration of the loop.
|
||||
if !arbitrary_self_types_enabled {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`
|
||||
// Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`.
|
||||
if !arbitrary_self_types_enabled {
|
||||
let trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
|
||||
Some(did) => did,
|
||||
|
|
@ -968,7 +978,7 @@ fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let mut err = error_392(tcx, span, param_name);
|
||||
|
||||
let suggested_marker_id = tcx.lang_items().phantom_data();
|
||||
// help is available only in presence of lang items
|
||||
// Help is available only in presence of lang items.
|
||||
if let Some(def_id) = suggested_marker_id {
|
||||
err.help(&format!("consider removing `{}` or using a marker such as `{}`",
|
||||
param_name,
|
||||
|
|
@ -988,12 +998,12 @@ fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) {
|
|||
}).collect();
|
||||
|
||||
for method_param in &generics.params {
|
||||
// Shadowing is checked in resolve_lifetime.
|
||||
// Shadowing is checked in `resolve_lifetime`.
|
||||
if let GenericParamDefKind::Lifetime = method_param.kind {
|
||||
continue
|
||||
}
|
||||
if impl_params.contains_key(&method_param.name) {
|
||||
// Tighten up the span to focus on only the shadowing type
|
||||
// Tighten up the span to focus on only the shadowing type.
|
||||
let type_span = tcx.def_span(method_param.def_id);
|
||||
|
||||
// The expectation here is that the original trait declaration is
|
||||
|
|
|
|||
|
|
@ -450,38 +450,38 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
let generics = self.tcx().generics_of(def_id);
|
||||
|
||||
let definition_ty = if generics.parent.is_some() {
|
||||
// impl trait
|
||||
// `impl Trait`
|
||||
self.fcx.infer_opaque_definition_from_instantiation(
|
||||
def_id,
|
||||
opaque_defn,
|
||||
instantiated_ty,
|
||||
)
|
||||
} else {
|
||||
// prevent
|
||||
// Prevent:
|
||||
// * `fn foo<T>() -> Foo<T>`
|
||||
// * `fn foo<T: Bound + Other>() -> Foo<T>`
|
||||
// from being defining
|
||||
// from being defining.
|
||||
|
||||
// Also replace all generic params with the ones from the existential type
|
||||
// definition so
|
||||
// definition so that
|
||||
// ```rust
|
||||
// existential type Foo<T>: 'static;
|
||||
// fn foo<U>() -> Foo<U> { .. }
|
||||
// ```
|
||||
// figures out the concrete type with `U`, but the stored type is with `T`
|
||||
// figures out the concrete type with `U`, but the stored type is with `T`.
|
||||
instantiated_ty.fold_with(&mut BottomUpFolder {
|
||||
tcx: self.tcx().global_tcx(),
|
||||
ty_op: |ty| {
|
||||
trace!("checking type {:?}", ty);
|
||||
// find a type parameter
|
||||
// Find a type parameter.
|
||||
if let ty::Param(..) = ty.sty {
|
||||
// look it up in the substitution list
|
||||
// Look it up in the substitution list.
|
||||
assert_eq!(opaque_defn.substs.len(), generics.params.len());
|
||||
for (subst, param) in opaque_defn.substs.iter().zip(&generics.params) {
|
||||
if let UnpackedKind::Type(subst) = subst.unpack() {
|
||||
if subst == ty {
|
||||
// found it in the substitution list, replace with the
|
||||
// parameter from the existential type
|
||||
// Found it in the substitution list; replace with the
|
||||
// parameter from the existential type.
|
||||
return self.tcx()
|
||||
.global_tcx()
|
||||
.mk_ty_param(param.index, param.name);
|
||||
|
|
@ -505,16 +505,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
},
|
||||
lt_op: |region| {
|
||||
match region {
|
||||
// Skip static and bound regions: they don't
|
||||
// require substitution.
|
||||
// Skip static and bound regions: they don't require substitution.
|
||||
ty::ReStatic | ty::ReLateBound(..) => region,
|
||||
_ => {
|
||||
trace!("checking {:?}", region);
|
||||
for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) {
|
||||
if let UnpackedKind::Lifetime(subst) = subst.unpack() {
|
||||
if subst == region {
|
||||
// found it in the substitution list, replace with the
|
||||
// parameter from the existential type
|
||||
// Found it in the substitution list; replace with the
|
||||
// parameter from the existential type.
|
||||
let reg = ty::EarlyBoundRegion {
|
||||
def_id: p.def_id,
|
||||
index: p.index,
|
||||
|
|
@ -586,8 +585,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
|
||||
if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty {
|
||||
if def_id == defin_ty_def_id {
|
||||
// Concrete type resolved to the existential type itself
|
||||
// Force a cycle error
|
||||
// Concrete type resolved to the existential type itself.
|
||||
// Force a cycle error.
|
||||
// FIXME(oli-obk): we could just not insert it into `concrete_existential_types`
|
||||
// which simply would make this use not a defining use.
|
||||
self.tcx().at(span).type_of(defin_ty_def_id);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! "Collection" is the process of determining the type and other external
|
||||
//! details of each item in Rust. Collection is specifically concerned
|
||||
//! with *interprocedural* things -- for example, for a function
|
||||
//! with *inter-procedural* things -- for example, for a function
|
||||
//! definition, collection will figure out the type and signature of the
|
||||
//! function, but it will not visit the *body* of the function in any way,
|
||||
//! nor examine type annotations on local variables (that's the job of
|
||||
|
|
@ -14,11 +14,10 @@
|
|||
//! At present, however, we do run collection across all items in the
|
||||
//! crate as a kind of pass. This should eventually be factored away.
|
||||
|
||||
use crate::astconv::{AstConv, Bounds};
|
||||
use crate::astconv::{AstConv, Bounds, SizedByDefault};
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::check::intrinsic::intrisic_operation_unsafety;
|
||||
use crate::lint;
|
||||
use crate::middle::lang_items::SizedTraitLangItem;
|
||||
use crate::middle::resolve_lifetime as rl;
|
||||
use crate::middle::weak_lang_items;
|
||||
use rustc::mir::mono::Linkage;
|
||||
|
|
@ -233,7 +232,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn set_tainted_by_errors(&self) {
|
||||
// no obvious place to track this, just let it go
|
||||
// no obvious place to track this, so just let it go
|
||||
}
|
||||
|
||||
fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
|
||||
|
|
@ -447,7 +446,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: hir::HirId) {
|
|||
}
|
||||
}
|
||||
|
||||
// Desugared from `impl Trait` -> visited by the function's return type
|
||||
// Desugared from `impl Trait`, so visited by the function's return type.
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: Some(_),
|
||||
..
|
||||
|
|
@ -704,7 +703,8 @@ fn super_predicates_of<'a, 'tcx>(
|
|||
|
||||
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
|
||||
let self_param_ty = tcx.mk_self_type();
|
||||
let superbounds1 = compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
|
||||
let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No,
|
||||
item.span);
|
||||
|
||||
let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
|
||||
|
||||
|
|
@ -1218,7 +1218,7 @@ pub fn checked_type_of<'a, 'tcx>(
|
|||
impl_trait_fn: None,
|
||||
..
|
||||
}) => find_existential_constraints(tcx, def_id),
|
||||
// existential types desugared from impl Trait
|
||||
// Existential types desugared from `impl Trait`.
|
||||
ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: Some(owner),
|
||||
..
|
||||
|
|
@ -1472,11 +1472,13 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
) -> Ty<'tcx> {
|
||||
use rustc::hir::{ImplItem, Item, TraitItem};
|
||||
|
||||
debug!("find_existential_constraints({:?})", def_id);
|
||||
|
||||
struct ConstraintLocator<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
// First found type span, actual type, mapping from the existential type's generic
|
||||
// parameters to the concrete type's generic parameters
|
||||
// (first found type span, actual type, mapping from the existential type's generic
|
||||
// parameters to the concrete type's generic parameters)
|
||||
//
|
||||
// The mapping is an index for each use site of a generic parameter in the concrete type
|
||||
//
|
||||
|
|
@ -1486,10 +1488,13 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
|
||||
impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> {
|
||||
fn check(&mut self, def_id: DefId) {
|
||||
trace!("checking {:?}", def_id);
|
||||
// don't try to check items that cannot possibly constrain the type
|
||||
// Don't try to check items that cannot possibly constrain the type.
|
||||
if !self.tcx.has_typeck_tables(def_id) {
|
||||
trace!("no typeck tables for {:?}", def_id);
|
||||
debug!(
|
||||
"find_existential_constraints: no constraint for `{:?}` at `{:?}`: no tables",
|
||||
self.def_id,
|
||||
def_id,
|
||||
);
|
||||
return;
|
||||
}
|
||||
let ty = self
|
||||
|
|
@ -1498,22 +1503,32 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
.concrete_existential_types
|
||||
.get(&self.def_id);
|
||||
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
|
||||
// FIXME(oli-obk): trace the actual span from inference to improve errors
|
||||
debug!(
|
||||
"find_existential_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
|
||||
self.def_id,
|
||||
def_id,
|
||||
ty,
|
||||
);
|
||||
|
||||
// FIXME(oli-obk): trace the actual span from inference to improve errors.
|
||||
let span = self.tcx.def_span(def_id);
|
||||
// used to quickly look up the position of a generic parameter
|
||||
let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
|
||||
// skip binder is ok, since we only use this to find generic parameters and their
|
||||
// positions.
|
||||
// Skipping binder is ok, since we only use this to find generic parameters and
|
||||
// their positions.
|
||||
for (idx, subst) in substs.iter().enumerate() {
|
||||
if let UnpackedKind::Type(ty) = subst.unpack() {
|
||||
if let ty::Param(p) = ty.sty {
|
||||
if index_map.insert(p, idx).is_some() {
|
||||
// there was already an entry for `p`, meaning a generic parameter
|
||||
// was used twice
|
||||
// There was already an entry for `p`, meaning a generic parameter
|
||||
// was used twice.
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
&format!("defining existential type use restricts existential \
|
||||
type by using the generic parameter `{}` twice", p.name),
|
||||
&format!(
|
||||
"defining existential type use restricts existential \
|
||||
type by using the generic parameter `{}` twice",
|
||||
p.name
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1528,8 +1543,8 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
// compute the index within the existential type for each generic parameter used in
|
||||
// the concrete type
|
||||
// Compute the index within the existential type for each generic parameter used in
|
||||
// the concrete type.
|
||||
let indices = concrete_type
|
||||
.subst(self.tcx, substs)
|
||||
.walk()
|
||||
|
|
@ -1550,14 +1565,15 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
let mut ty = concrete_type.walk().fuse();
|
||||
let mut p_ty = prev_ty.walk().fuse();
|
||||
let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) {
|
||||
// type parameters are equal to any other type parameter for the purpose of
|
||||
// Type parameters are equal to any other type parameter for the purpose of
|
||||
// concrete type equality, as it is possible to obtain the same type just
|
||||
// by passing matching parameters to a function.
|
||||
(ty::Param(_), ty::Param(_)) => true,
|
||||
_ => t == p,
|
||||
});
|
||||
if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
|
||||
// found different concrete types for the existential type
|
||||
debug!("find_existential_constraints: span={:?}", span);
|
||||
// Found different concrete types for the existential type.
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
span,
|
||||
"concrete type differs from previous defining existential type use",
|
||||
|
|
@ -1569,7 +1585,7 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
err.span_note(prev_span, "previous use here");
|
||||
err.emit();
|
||||
} else if indices != *prev_indices {
|
||||
// found "same" concrete types, but the generic parameter order differs
|
||||
// Found "same" concrete types, but the generic parameter order differs.
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
span,
|
||||
"concrete type's generic parameters differ from previous defining use",
|
||||
|
|
@ -1597,6 +1613,12 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
} else {
|
||||
self.found = Some((span, concrete_type, indices));
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
"find_existential_constraints: no constraint for `{:?}` at `{:?}`",
|
||||
self.def_id,
|
||||
def_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1607,7 +1629,7 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
}
|
||||
fn visit_item(&mut self, it: &'tcx Item) {
|
||||
let def_id = self.tcx.hir().local_def_id_from_hir_id(it.hir_id);
|
||||
// the existential type itself or its children are not within its reveal scope
|
||||
// The existential type itself or its children are not within its reveal scope.
|
||||
if def_id != self.def_id {
|
||||
self.check(def_id);
|
||||
intravisit::walk_item(self, it);
|
||||
|
|
@ -1615,7 +1637,7 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
}
|
||||
fn visit_impl_item(&mut self, it: &'tcx ImplItem) {
|
||||
let def_id = self.tcx.hir().local_def_id_from_hir_id(it.hir_id);
|
||||
// the existential type itself or its children are not within its reveal scope
|
||||
// The existential type itself or its children are not within its reveal scope.
|
||||
if def_id != self.def_id {
|
||||
self.check(def_id);
|
||||
intravisit::walk_impl_item(self, it);
|
||||
|
|
@ -1628,26 +1650,28 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
let scope = tcx.hir()
|
||||
.get_defining_scope(hir_id)
|
||||
.expect("could not get defining scope");
|
||||
let mut locator = ConstraintLocator {
|
||||
def_id,
|
||||
tcx,
|
||||
found: None,
|
||||
};
|
||||
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
let parent = tcx.hir().get_parent_item(hir_id);
|
||||
|
||||
trace!("parent_id: {:?}", parent);
|
||||
debug!("find_existential_constraints: scope={:?}", scope);
|
||||
|
||||
if parent == hir::CRATE_HIR_ID {
|
||||
if scope == hir::CRATE_HIR_ID {
|
||||
intravisit::walk_crate(&mut locator, tcx.hir().krate());
|
||||
} else {
|
||||
trace!("parent: {:?}", tcx.hir().get_by_hir_id(parent));
|
||||
match tcx.hir().get_by_hir_id(parent) {
|
||||
debug!("find_existential_constraints: scope={:?}", tcx.hir().get_by_hir_id(scope));
|
||||
match tcx.hir().get_by_hir_id(scope) {
|
||||
Node::Item(ref it) => intravisit::walk_item(&mut locator, it),
|
||||
Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
|
||||
Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it),
|
||||
other => bug!(
|
||||
"{:?} is not a valid parent of an existential type item",
|
||||
"{:?} is not a valid scope for an existential type item",
|
||||
other
|
||||
),
|
||||
}
|
||||
|
|
@ -1765,57 +1789,6 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> hir::I
|
|||
}
|
||||
}
|
||||
|
||||
// Is it marked with ?Sized
|
||||
fn is_unsized<'gcx: 'tcx, 'tcx>(
|
||||
astconv: &dyn AstConv<'gcx, 'tcx>,
|
||||
ast_bounds: &[hir::GenericBound],
|
||||
span: Span,
|
||||
) -> bool {
|
||||
let tcx = astconv.tcx();
|
||||
|
||||
// Try to find an unbound in bounds.
|
||||
let mut unbound = None;
|
||||
for ab in ast_bounds {
|
||||
if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
|
||||
if unbound.is_none() {
|
||||
unbound = Some(ptr.trait_ref.clone());
|
||||
} else {
|
||||
span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0203,
|
||||
"type parameter has more than one relaxed default \
|
||||
bound, only one is supported"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let kind_id = tcx.lang_items().require(SizedTraitLangItem);
|
||||
match unbound {
|
||||
Some(ref tpb) => {
|
||||
// FIXME(#8559) currently requires the unbound to be built-in.
|
||||
if let Ok(kind_id) = kind_id {
|
||||
if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
|
||||
tcx.sess.span_warn(
|
||||
span,
|
||||
"default bound relaxed for a type parameter, but \
|
||||
this does nothing because the given bound is not \
|
||||
a default. Only `?Sized` is supported",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ if kind_id.is_ok() => {
|
||||
return false;
|
||||
}
|
||||
// No lang item for Sized, so we can't add it as a bound.
|
||||
None => {}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns the early-bound lifetimes declared in this generics
|
||||
/// listing. For anything other than fns/methods, this is just all
|
||||
/// the lifetimes that are declared. For fns or methods, we have to
|
||||
|
|
@ -1960,8 +1933,8 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
let opaque_ty = tcx.mk_opaque(def_id, substs);
|
||||
|
||||
// Collect the bounds, i.e., the `A+B+'c` in `impl A+B+'c`.
|
||||
let bounds = compute_bounds(
|
||||
// Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
|
||||
let bounds = AstConv::compute_bounds(
|
||||
&icx,
|
||||
opaque_ty,
|
||||
bounds,
|
||||
|
|
@ -2006,8 +1979,8 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
let opaque_ty = tcx.mk_opaque(def_id, substs);
|
||||
|
||||
// Collect the bounds, i.e., the `A+B+'c` in `impl A+B+'c`.
|
||||
let bounds = compute_bounds(
|
||||
// Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
|
||||
let bounds = AstConv::compute_bounds(
|
||||
&icx,
|
||||
opaque_ty,
|
||||
bounds,
|
||||
|
|
@ -2015,15 +1988,16 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
tcx.def_span(def_id),
|
||||
);
|
||||
|
||||
let bounds_predicates = bounds.predicates(tcx, opaque_ty);
|
||||
if impl_trait_fn.is_some() {
|
||||
// impl Trait
|
||||
// opaque types
|
||||
return tcx.arena.alloc(ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: bounds.predicates(tcx, opaque_ty),
|
||||
predicates: bounds_predicates,
|
||||
});
|
||||
} else {
|
||||
// named existential types
|
||||
predicates.extend(bounds.predicates(tcx, opaque_ty));
|
||||
predicates.extend(bounds_predicates);
|
||||
generics
|
||||
}
|
||||
}
|
||||
|
|
@ -2093,7 +2067,7 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
}
|
||||
|
||||
// Collect the predicates that were written inline by the user on each
|
||||
// type parameter (e.g., `<T:Foo>`).
|
||||
// type parameter (e.g., `<T: Foo>`).
|
||||
for param in &ast_generics.params {
|
||||
if let GenericParamKind::Type { .. } = param.kind {
|
||||
let name = param.name.ident().as_interned_str();
|
||||
|
|
@ -2101,12 +2075,12 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
index += 1;
|
||||
|
||||
let sized = SizedByDefault::Yes;
|
||||
let bounds = compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span);
|
||||
let bounds = AstConv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span);
|
||||
predicates.extend(bounds.predicates(tcx, param_ty));
|
||||
}
|
||||
}
|
||||
|
||||
// Add in the bounds that appear in the where-clause
|
||||
// Add in the bounds that appear in the where-clause.
|
||||
let where_clause = &ast_generics.where_clause;
|
||||
for predicate in &where_clause.predicates {
|
||||
match predicate {
|
||||
|
|
@ -2136,19 +2110,17 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
for bound in bound_pred.bounds.iter() {
|
||||
match bound {
|
||||
&hir::GenericBound::Trait(ref poly_trait_ref, _) => {
|
||||
let mut projections = Vec::new();
|
||||
let mut bounds = Bounds::default();
|
||||
|
||||
let (trait_ref, _) = AstConv::instantiate_poly_trait_ref(
|
||||
&icx,
|
||||
poly_trait_ref,
|
||||
ty,
|
||||
&mut projections,
|
||||
&mut bounds,
|
||||
);
|
||||
|
||||
predicates.extend(
|
||||
iter::once((trait_ref.to_predicate(), poly_trait_ref.span)).chain(
|
||||
projections.iter().map(|&(p, span)| (p.to_predicate(), span)
|
||||
)));
|
||||
predicates.push((trait_ref.to_predicate(), poly_trait_ref.span));
|
||||
predicates.extend(bounds.predicates(tcx, ty));
|
||||
}
|
||||
|
||||
&hir::GenericBound::Outlives(ref lifetime) => {
|
||||
|
|
@ -2187,14 +2159,14 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
let trait_item = tcx.hir().trait_item(trait_item_ref.id);
|
||||
let bounds = match trait_item.node {
|
||||
hir::TraitItemKind::Type(ref bounds, _) => bounds,
|
||||
_ => return vec![].into_iter()
|
||||
_ => return Vec::new().into_iter()
|
||||
};
|
||||
|
||||
let assoc_ty =
|
||||
tcx.mk_projection(tcx.hir().local_def_id_from_hir_id(trait_item.hir_id),
|
||||
self_trait_ref.substs);
|
||||
|
||||
let bounds = compute_bounds(
|
||||
let bounds = AstConv::compute_bounds(
|
||||
&ItemCtxt::new(tcx, def_id),
|
||||
assoc_ty,
|
||||
bounds,
|
||||
|
|
@ -2236,68 +2208,6 @@ fn explicit_predicates_of<'a, 'tcx>(
|
|||
result
|
||||
}
|
||||
|
||||
pub enum SizedByDefault {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
|
||||
/// or a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
|
||||
/// built-in trait `Send`.
|
||||
pub fn compute_bounds<'gcx: 'tcx, 'tcx>(
|
||||
astconv: &dyn AstConv<'gcx, 'tcx>,
|
||||
param_ty: Ty<'tcx>,
|
||||
ast_bounds: &[hir::GenericBound],
|
||||
sized_by_default: SizedByDefault,
|
||||
span: Span,
|
||||
) -> Bounds<'tcx> {
|
||||
let mut region_bounds = Vec::new();
|
||||
let mut trait_bounds = Vec::new();
|
||||
|
||||
for ast_bound in ast_bounds {
|
||||
match *ast_bound {
|
||||
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => trait_bounds.push(b),
|
||||
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
|
||||
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
|
||||
}
|
||||
}
|
||||
|
||||
let mut projection_bounds = Vec::new();
|
||||
|
||||
let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
|
||||
let (poly_trait_ref, _) = astconv.instantiate_poly_trait_ref(
|
||||
bound,
|
||||
param_ty,
|
||||
&mut projection_bounds,
|
||||
);
|
||||
(poly_trait_ref, bound.span)
|
||||
}).collect();
|
||||
|
||||
let region_bounds = region_bounds
|
||||
.into_iter()
|
||||
.map(|r| (astconv.ast_region_to_region(r, None), r.span))
|
||||
.collect();
|
||||
|
||||
trait_bounds.sort_by_key(|(t, _)| t.def_id());
|
||||
|
||||
let implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
|
||||
if !is_unsized(astconv, ast_bounds, span) {
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Bounds {
|
||||
region_bounds,
|
||||
implicitly_sized,
|
||||
trait_bounds,
|
||||
projection_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a specific `GenericBound` from the AST into a set of
|
||||
/// predicates that apply to the self type. A vector is returned
|
||||
/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
|
||||
|
|
@ -2310,13 +2220,11 @@ fn predicates_from_bound<'tcx>(
|
|||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
match *bound {
|
||||
hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
|
||||
let mut projections = Vec::new();
|
||||
let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut projections);
|
||||
iter::once((pred.to_predicate(), tr.span)).chain(
|
||||
projections
|
||||
.into_iter()
|
||||
.map(|(p, span)| (p.to_predicate(), span))
|
||||
).collect()
|
||||
let mut bounds = Bounds::default();
|
||||
let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds);
|
||||
iter::once((pred.to_predicate(), tr.span))
|
||||
.chain(bounds.predicates(astconv.tcx(), param_ty))
|
||||
.collect()
|
||||
}
|
||||
hir::GenericBound::Outlives(ref lifetime) => {
|
||||
let region = astconv.ast_region_to_region(lifetime, None);
|
||||
|
|
@ -2340,8 +2248,8 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
|
|||
};
|
||||
let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl);
|
||||
|
||||
// feature gate SIMD types in FFI, since I (huonw) am not sure the
|
||||
// ABIs are handled at all correctly.
|
||||
// Feature gate SIMD types in FFI, since I am not sure that the
|
||||
// ABIs are handled at all correctly. -huonw
|
||||
if abi != abi::Abi::RustIntrinsic
|
||||
&& abi != abi::Abi::PlatformIntrinsic
|
||||
&& !tcx.features().simd_ffi
|
||||
|
|
@ -2416,13 +2324,13 @@ fn from_target_feature(
|
|||
};
|
||||
let rust_features = tcx.features();
|
||||
for item in list {
|
||||
// Only `enable = ...` is accepted in the meta item list
|
||||
// Only `enable = ...` is accepted in the meta-item list.
|
||||
if !item.check_name(sym::enable) {
|
||||
bad_item(item.span());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Must be of the form `enable = "..."` ( a string)
|
||||
// Must be of the form `enable = "..."` (a string).
|
||||
let value = match item.value_str() {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
|
|
@ -2431,9 +2339,9 @@ fn from_target_feature(
|
|||
}
|
||||
};
|
||||
|
||||
// We allow comma separation to enable multiple features
|
||||
// We allow comma separation to enable multiple features.
|
||||
target_features.extend(value.as_str().split(',').filter_map(|feature| {
|
||||
// Only allow whitelisted features per platform
|
||||
// Only allow whitelisted features per platform.
|
||||
let feature_gate = match whitelist.get(feature) {
|
||||
Some(g) => g,
|
||||
None => {
|
||||
|
|
@ -2457,7 +2365,7 @@ fn from_target_feature(
|
|||
}
|
||||
};
|
||||
|
||||
// Only allow features whose feature gates have been enabled
|
||||
// Only allow features whose feature gates have been enabled.
|
||||
let allowed = match feature_gate.as_ref().map(|s| *s) {
|
||||
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
|
||||
Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature,
|
||||
|
|
@ -2545,7 +2453,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
|
|||
if tcx.is_foreign_item(id) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
|
||||
} else {
|
||||
// `#[ffi_returns_twice]` is only allowed `extern fn`s
|
||||
// `#[ffi_returns_twice]` is only allowed `extern fn`s.
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ use util::common::time;
|
|||
|
||||
use std::iter;
|
||||
|
||||
use astconv::{AstConv, Bounds};
|
||||
pub use collect::checked_type_of;
|
||||
|
||||
pub struct TypeAndSubsts<'tcx> {
|
||||
|
|
@ -379,8 +380,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
|||
/// A quasi-deprecated helper used in rustdoc and clippy to get
|
||||
/// the type from a HIR node.
|
||||
pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> {
|
||||
// In case there are any projections etc, find the "environment"
|
||||
// def-id that will be used to determine the traits/predicates in
|
||||
// In case there are any projections, etc., find the "environment"
|
||||
// def-ID that will be used to determine the traits/predicates in
|
||||
// scope. This is derived from the enclosing item-like thing.
|
||||
let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
|
||||
let env_def_id = tcx.hir().local_def_id_from_hir_id(env_node_id);
|
||||
|
|
@ -390,19 +391,19 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) ->
|
|||
}
|
||||
|
||||
pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
|
||||
-> (ty::PolyTraitRef<'tcx>, Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>) {
|
||||
// In case there are any projections etc, find the "environment"
|
||||
// def-id that will be used to determine the traits/predicates in
|
||||
-> (ty::PolyTraitRef<'tcx>, Bounds<'tcx>) {
|
||||
// In case there are any projections, etc., find the "environment"
|
||||
// def-ID that will be used to determine the traits/predicates in
|
||||
// scope. This is derived from the enclosing item-like thing.
|
||||
let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
|
||||
let env_def_id = tcx.hir().local_def_id_from_hir_id(env_hir_id);
|
||||
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
|
||||
let mut projections = Vec::new();
|
||||
let (principal, _) = astconv::AstConv::instantiate_poly_trait_ref_inner(
|
||||
&item_cx, hir_trait, tcx.types.err, &mut projections, true
|
||||
let mut bounds = Bounds::default();
|
||||
let (principal, _) = AstConv::instantiate_poly_trait_ref_inner(
|
||||
&item_cx, hir_trait, tcx.types.err, &mut bounds, true
|
||||
);
|
||||
|
||||
(principal, projections)
|
||||
(principal, bounds)
|
||||
}
|
||||
|
||||
__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
|
||||
|
|
|
|||
|
|
@ -626,7 +626,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
} => {
|
||||
bindings.push(TypeBinding {
|
||||
name: left_name.clone(),
|
||||
ty: rhs,
|
||||
kind: TypeBindingKind::Equality {
|
||||
ty: rhs,
|
||||
},
|
||||
});
|
||||
}
|
||||
&mut GenericArgs::Parenthesized { .. } => {
|
||||
|
|
|
|||
|
|
@ -1979,7 +1979,7 @@ impl FnDecl {
|
|||
match &bounds[0] {
|
||||
GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
|
||||
let bindings = trait_.bindings().unwrap();
|
||||
FunctionRetTy::Return(bindings[0].ty.clone())
|
||||
FunctionRetTy::Return(bindings[0].ty().clone())
|
||||
}
|
||||
_ => panic!("unexpected desugaring of async function"),
|
||||
}
|
||||
|
|
@ -2443,12 +2443,12 @@ pub struct PolyTrait {
|
|||
pub generic_params: Vec<GenericParamDef>,
|
||||
}
|
||||
|
||||
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
|
||||
/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
|
||||
/// it does not preserve mutability or boxes.
|
||||
/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
|
||||
/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
|
||||
/// importantly, it does not preserve mutability or boxes.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum Type {
|
||||
/// Structs/enums/traits (most that'd be an `hir::TyKind::Path`).
|
||||
/// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
|
||||
ResolvedPath {
|
||||
path: Path,
|
||||
param_names: Option<Vec<GenericBound>>,
|
||||
|
|
@ -2462,7 +2462,7 @@ pub enum Type {
|
|||
/// Primitives are the fixed-size numeric types (plus int/usize/float), char,
|
||||
/// arrays, slices, and tuples.
|
||||
Primitive(PrimitiveType),
|
||||
/// extern "ABI" fn
|
||||
/// `extern "ABI" fn`
|
||||
BareFunction(Box<BareFunctionDecl>),
|
||||
Tuple(Vec<Type>),
|
||||
Slice(Box<Type>),
|
||||
|
|
@ -2477,17 +2477,17 @@ pub enum Type {
|
|||
type_: Box<Type>,
|
||||
},
|
||||
|
||||
// <Type as Trait>::Name
|
||||
// `<Type as Trait>::Name`
|
||||
QPath {
|
||||
name: String,
|
||||
self_type: Box<Type>,
|
||||
trait_: Box<Type>
|
||||
},
|
||||
|
||||
// _
|
||||
// `_`
|
||||
Infer,
|
||||
|
||||
// impl TraitA+TraitB
|
||||
// `impl TraitA + TraitB + ...`
|
||||
ImplTrait(Vec<GenericBound>),
|
||||
}
|
||||
|
||||
|
|
@ -2747,7 +2747,6 @@ impl Clean<Type> for hir::Ty {
|
|||
|
||||
match self.node {
|
||||
TyKind::Never => Never,
|
||||
TyKind::CVarArgs(_) => CVarArgs,
|
||||
TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
|
||||
TyKind::Rptr(ref l, ref m) => {
|
||||
let lifetime = if l.is_elided() {
|
||||
|
|
@ -2933,12 +2932,13 @@ impl Clean<Type> for hir::Ty {
|
|||
}
|
||||
ResolvedPath { path, param_names: Some(bounds), did, is_generic, }
|
||||
}
|
||||
_ => Infer // shouldn't happen
|
||||
_ => Infer, // shouldn't happen
|
||||
}
|
||||
}
|
||||
TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
|
||||
TyKind::Infer | TyKind::Err => Infer,
|
||||
TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node),
|
||||
TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.node),
|
||||
TyKind::CVarArgs(_) => CVarArgs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3054,7 +3054,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
|||
for pb in obj.projection_bounds() {
|
||||
bindings.push(TypeBinding {
|
||||
name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx),
|
||||
ty: pb.skip_binder().ty.clean(cx)
|
||||
kind: TypeBindingKind::Equality {
|
||||
ty: pb.skip_binder().ty.clean(cx)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -3110,7 +3112,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
|||
Some(TypeBinding {
|
||||
name: cx.tcx.associated_item(proj.projection_ty.item_def_id)
|
||||
.ident.name.clean(cx),
|
||||
ty: proj.ty.clean(cx),
|
||||
kind: TypeBindingKind::Equality {
|
||||
ty: proj.ty.clean(cx),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
|
@ -3495,7 +3499,7 @@ pub enum GenericArgs {
|
|||
impl Clean<GenericArgs> for hir::GenericArgs {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
|
||||
if self.parenthesized {
|
||||
let output = self.bindings[0].ty.clean(cx);
|
||||
let output = self.bindings[0].ty().clean(cx);
|
||||
GenericArgs::Parenthesized {
|
||||
inputs: self.inputs().clean(cx),
|
||||
output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
|
||||
|
|
@ -4343,18 +4347,53 @@ impl Clean<Deprecation> for attr::Deprecation {
|
|||
}
|
||||
}
|
||||
|
||||
/// An equality constraint on an associated type, e.g., `A = Bar` in `Foo<A = Bar>`
|
||||
/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
|
||||
/// `A: Send + Sync` in `Foo<A: Send + Sync>`).
|
||||
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)]
|
||||
pub struct TypeBinding {
|
||||
pub name: String,
|
||||
pub ty: Type
|
||||
pub kind: TypeBindingKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)]
|
||||
pub enum TypeBindingKind {
|
||||
Equality {
|
||||
ty: Type,
|
||||
},
|
||||
Constraint {
|
||||
bounds: Vec<GenericBound>,
|
||||
},
|
||||
}
|
||||
|
||||
impl TypeBinding {
|
||||
pub fn ty(&self) -> &Type {
|
||||
match self.kind {
|
||||
TypeBindingKind::Equality { ref ty } => ty,
|
||||
_ => panic!("expected equality type binding for parenthesized generic args"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<TypeBinding> for hir::TypeBinding {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
|
||||
TypeBinding {
|
||||
name: self.ident.name.clean(cx),
|
||||
ty: self.ty.clean(cx)
|
||||
kind: self.kind.clean(cx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<TypeBindingKind> for hir::TypeBindingKind {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> TypeBindingKind {
|
||||
match *self {
|
||||
hir::TypeBindingKind::Equality { ref ty } =>
|
||||
TypeBindingKind::Equality {
|
||||
ty: ty.clean(cx),
|
||||
},
|
||||
hir::TypeBindingKind::Constraint { ref bounds } =>
|
||||
TypeBindingKind::Constraint {
|
||||
bounds: bounds.into_iter().map(|b| b.clean(cx)).collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,9 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
|
|||
PP::AngleBracketed { ref mut bindings, .. } => {
|
||||
bindings.push(clean::TypeBinding {
|
||||
name: name.clone(),
|
||||
ty: rhs.clone(),
|
||||
kind: clean::TypeBindingKind::Equality {
|
||||
ty: rhs.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
PP::Parenthesized { ref mut output, .. } => {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ use crate::core::DocAccessLevels;
|
|||
use crate::html::item_type::ItemType;
|
||||
use crate::html::render::{self, cache, CURRENT_LOCATION_KEY};
|
||||
|
||||
|
||||
/// Helper to render an optional visibility with a space after it (if the
|
||||
/// visibility is preset)
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -561,7 +560,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
|
|||
if param_names.is_some() {
|
||||
f.write_str("dyn ")?;
|
||||
}
|
||||
// Paths like T::Output and Self::Output should be rendered with all segments
|
||||
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
|
||||
resolved_path(f, did, path, is_generic, use_absolute)?;
|
||||
tybounds(f, param_names)
|
||||
}
|
||||
|
|
@ -585,7 +584,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
|
|||
&[] => primitive_link(f, PrimitiveType::Unit, "()"),
|
||||
&[ref one] => {
|
||||
primitive_link(f, PrimitiveType::Tuple, "(")?;
|
||||
//carry f.alternate() into this display w/o branching manually
|
||||
// Carry `f.alternate()` into this display w/o branching manually.
|
||||
fmt::Display::fmt(one, f)?;
|
||||
primitive_link(f, PrimitiveType::Tuple, ",)")
|
||||
}
|
||||
|
|
@ -638,7 +637,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) ->
|
|||
"&".to_string()
|
||||
};
|
||||
match **ty {
|
||||
clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T]
|
||||
clean::Slice(ref bt) => { // `BorrowedRef{ ... Slice(T) }` is `&[T]`
|
||||
match **bt {
|
||||
clean::Generic(_) => {
|
||||
if f.alternate() {
|
||||
|
|
@ -1020,11 +1019,26 @@ impl fmt::Display for clean::ImportSource {
|
|||
|
||||
impl fmt::Display for clean::TypeBinding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if f.alternate() {
|
||||
write!(f, "{} = {:#}", self.name, self.ty)
|
||||
} else {
|
||||
write!(f, "{} = {}", self.name, self.ty)
|
||||
f.write_str(&self.name)?;
|
||||
match self.kind {
|
||||
clean::TypeBindingKind::Equality { ref ty } => {
|
||||
if f.alternate() {
|
||||
write!(f, " = {:#}", ty)?;
|
||||
} else {
|
||||
write!(f, " = {}", ty)?;
|
||||
}
|
||||
}
|
||||
clean::TypeBindingKind::Constraint { ref bounds } => {
|
||||
if !bounds.is_empty() {
|
||||
if f.alternate() {
|
||||
write!(f, ": {:#}", GenericBounds(bounds))?;
|
||||
} else {
|
||||
write!(f, ": {}", GenericBounds(bounds))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,8 @@ fn default_hook(info: &PanicInfo<'_>) {
|
|||
}
|
||||
};
|
||||
|
||||
let location = info.location().unwrap(); // The current implementation always returns Some
|
||||
// The current implementation always returns `Some`.
|
||||
let location = info.location().unwrap();
|
||||
|
||||
let msg = match info.payload().downcast_ref::<&'static str>() {
|
||||
Some(s) => *s,
|
||||
|
|
@ -196,7 +197,7 @@ fn default_hook(info: &PanicInfo<'_>) {
|
|||
if let Some(format) = log_backtrace {
|
||||
let _ = backtrace::print(err, format);
|
||||
} else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
|
||||
let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` \
|
||||
let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \
|
||||
environment variable to display a backtrace.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ impl<'a, 'b> Printer<'a, 'b> {
|
|||
Some(symbol) => {
|
||||
match self.format {
|
||||
PrintFormat::Full => write!(self.out, "{}", symbol)?,
|
||||
// strip the trailing hash if short mode
|
||||
// Strip the trailing hash if short mode.
|
||||
PrintFormat::Short => write!(self.out, "{:#}", symbol)?,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,9 +190,9 @@ pub struct AngleBracketedArgs {
|
|||
pub span: Span,
|
||||
/// The arguments for this path segment.
|
||||
pub args: Vec<GenericArg>,
|
||||
/// Bindings (equality constraints) on associated types, if present.
|
||||
/// E.g., `Foo<A = Bar>`.
|
||||
pub bindings: Vec<TypeBinding>,
|
||||
/// Constraints on associated types, if any.
|
||||
/// E.g., `Foo<A = Bar, B: Baz>`.
|
||||
pub constraints: Vec<AssocTyConstraint>,
|
||||
}
|
||||
|
||||
impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
|
||||
|
|
@ -213,7 +213,7 @@ pub struct ParenthesizedArgs {
|
|||
/// Overall span
|
||||
pub span: Span,
|
||||
|
||||
/// `(A,B)`
|
||||
/// `(A, B)`
|
||||
pub inputs: Vec<P<Ty>>,
|
||||
|
||||
/// `C`
|
||||
|
|
@ -225,7 +225,7 @@ impl ParenthesizedArgs {
|
|||
AngleBracketedArgs {
|
||||
span: self.span,
|
||||
args: self.inputs.iter().cloned().map(|input| GenericArg::Type(input)).collect(),
|
||||
bindings: vec![],
|
||||
constraints: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1611,15 +1611,29 @@ impl fmt::Display for UintTy {
|
|||
}
|
||||
}
|
||||
|
||||
// Bind a type to an associated type: `A = Foo`.
|
||||
/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
|
||||
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct TypeBinding {
|
||||
pub struct AssocTyConstraint {
|
||||
pub id: NodeId,
|
||||
pub ident: Ident,
|
||||
pub ty: P<Ty>,
|
||||
pub kind: AssocTyConstraintKind,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// The kinds of an `AssocTyConstraint`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum AssocTyConstraintKind {
|
||||
/// E.g., `A = Bar` in `Foo<A = Bar>`.
|
||||
Equality {
|
||||
ty: P<Ty>,
|
||||
},
|
||||
/// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
|
||||
Bound {
|
||||
bounds: GenericBounds,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct Ty {
|
||||
pub id: NodeId,
|
||||
|
|
@ -1840,7 +1854,7 @@ impl Arg {
|
|||
}
|
||||
}
|
||||
|
||||
/// Header (not the body) of a function declaration.
|
||||
/// A header (not the body) of a function declaration.
|
||||
///
|
||||
/// E.g., `fn foo(bar: baz)`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_target::spec::abi::Abi;
|
|||
use syntax_pos::{Pos, Span};
|
||||
|
||||
pub trait AstBuilder {
|
||||
// paths
|
||||
// Paths
|
||||
fn path(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path;
|
||||
fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path;
|
||||
fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path;
|
||||
|
|
@ -18,7 +18,7 @@ pub trait AstBuilder {
|
|||
global: bool,
|
||||
idents: Vec<ast::Ident>,
|
||||
args: Vec<ast::GenericArg>,
|
||||
bindings: Vec<ast::TypeBinding>)
|
||||
constraints: Vec<ast::AssocTyConstraint>)
|
||||
-> ast::Path;
|
||||
|
||||
fn qpath(&self, self_type: P<ast::Ty>,
|
||||
|
|
@ -29,7 +29,7 @@ pub trait AstBuilder {
|
|||
trait_path: ast::Path,
|
||||
ident: ast::Ident,
|
||||
args: Vec<ast::GenericArg>,
|
||||
bindings: Vec<ast::TypeBinding>)
|
||||
constraints: Vec<ast::AssocTyConstraint>)
|
||||
-> (ast::QSelf, ast::Path);
|
||||
|
||||
// types and consts
|
||||
|
|
@ -69,7 +69,7 @@ pub trait AstBuilder {
|
|||
bounds: ast::GenericBounds)
|
||||
-> ast::GenericParam;
|
||||
|
||||
// statements
|
||||
// Statements
|
||||
fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt;
|
||||
fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt;
|
||||
fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident, ex: P<ast::Expr>) -> ast::Stmt;
|
||||
|
|
@ -83,11 +83,11 @@ pub trait AstBuilder {
|
|||
fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt;
|
||||
fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;
|
||||
|
||||
// blocks
|
||||
// Blocks
|
||||
fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block>;
|
||||
fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block>;
|
||||
|
||||
// expressions
|
||||
// Expressions
|
||||
fn expr(&self, span: Span, node: ast::ExprKind) -> P<ast::Expr>;
|
||||
fn expr_path(&self, path: ast::Path) -> P<ast::Expr>;
|
||||
fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr>;
|
||||
|
|
@ -194,12 +194,12 @@ pub trait AstBuilder {
|
|||
fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
|
||||
ident: ast::Ident) -> P<ast::Expr>;
|
||||
|
||||
// items
|
||||
// Items
|
||||
fn item(&self, span: Span,
|
||||
name: Ident, attrs: Vec<ast::Attribute> , node: ast::ItemKind) -> P<ast::Item>;
|
||||
|
||||
fn arg(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::Arg;
|
||||
// FIXME unused self
|
||||
// FIXME: unused `self`
|
||||
fn fn_decl(&self, inputs: Vec<ast::Arg> , output: ast::FunctionRetTy) -> P<ast::FnDecl>;
|
||||
|
||||
fn item_fn_poly(&self,
|
||||
|
|
@ -302,7 +302,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
global: bool,
|
||||
mut idents: Vec<ast::Ident> ,
|
||||
args: Vec<ast::GenericArg>,
|
||||
bindings: Vec<ast::TypeBinding> )
|
||||
constraints: Vec<ast::AssocTyConstraint> )
|
||||
-> ast::Path {
|
||||
assert!(!idents.is_empty());
|
||||
let add_root = global && !idents[0].is_path_segment_keyword();
|
||||
|
|
@ -314,8 +314,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
segments.extend(idents.into_iter().map(|ident| {
|
||||
ast::PathSegment::from_ident(ident.with_span_pos(span))
|
||||
}));
|
||||
let args = if !args.is_empty() || !bindings.is_empty() {
|
||||
ast::AngleBracketedArgs { args, bindings, span }.into()
|
||||
let args = if !args.is_empty() || !constraints.is_empty() {
|
||||
ast::AngleBracketedArgs { args, constraints, span }.into()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -346,11 +346,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
trait_path: ast::Path,
|
||||
ident: ast::Ident,
|
||||
args: Vec<ast::GenericArg>,
|
||||
bindings: Vec<ast::TypeBinding>)
|
||||
constraints: Vec<ast::AssocTyConstraint>)
|
||||
-> (ast::QSelf, ast::Path) {
|
||||
let mut path = trait_path;
|
||||
let args = if !args.is_empty() || !bindings.is_empty() {
|
||||
ast::AngleBracketedArgs { args, bindings, span: ident.span }.into()
|
||||
let args = if !args.is_empty() || !constraints.is_empty() {
|
||||
ast::AngleBracketedArgs { args, constraints, span: ident.span }.into()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -552,7 +552,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Generate `let _: Type;`, usually used for type assertions.
|
||||
// Generates `let _: Type;`, which is usually used for type assertions.
|
||||
fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
|
||||
let local = P(ast::Local {
|
||||
pat: self.pat_wild(span),
|
||||
|
|
@ -606,7 +606,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
self.expr(path.span, ast::ExprKind::Path(None, path))
|
||||
}
|
||||
|
||||
/// Constructs a QPath expression.
|
||||
/// Constructs a `QPath` expression.
|
||||
fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr> {
|
||||
self.expr(span, ast::ExprKind::Path(Some(qself), path))
|
||||
}
|
||||
|
|
@ -736,7 +736,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
self.expr(sp, ast::ExprKind::Cast(expr, ty))
|
||||
}
|
||||
|
||||
|
||||
fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
|
||||
let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
|
||||
self.expr_call_global(sp, some, vec![expr])
|
||||
|
|
@ -748,12 +747,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
self.expr_path(none)
|
||||
}
|
||||
|
||||
|
||||
fn expr_break(&self, sp: Span) -> P<ast::Expr> {
|
||||
self.expr(sp, ast::ExprKind::Break(None, None))
|
||||
}
|
||||
|
||||
|
||||
fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
|
||||
self.expr(sp, ast::ExprKind::Tup(exprs))
|
||||
}
|
||||
|
|
@ -797,22 +794,22 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
let binding_pat = self.pat_ident(sp, binding_variable);
|
||||
let binding_expr = self.expr_ident(sp, binding_variable);
|
||||
|
||||
// Ok(__try_var) pattern
|
||||
// `Ok(__try_var)` pattern
|
||||
let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]);
|
||||
|
||||
// Err(__try_var) (pattern and expression resp.)
|
||||
// `Err(__try_var)` (pattern and expression respectively)
|
||||
let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
|
||||
let err_inner_expr = self.expr_call(sp, self.expr_path(err_path),
|
||||
vec![binding_expr.clone()]);
|
||||
// return Err(__try_var)
|
||||
// `return Err(__try_var)`
|
||||
let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr)));
|
||||
|
||||
// Ok(__try_var) => __try_var
|
||||
// `Ok(__try_var) => __try_var`
|
||||
let ok_arm = self.arm(sp, vec![ok_pat], binding_expr);
|
||||
// Err(__try_var) => return Err(__try_var)
|
||||
// `Err(__try_var) => return Err(__try_var)`
|
||||
let err_arm = self.arm(sp, vec![err_pat], err_expr);
|
||||
|
||||
// match head { Ok() => ..., Err() => ... }
|
||||
// `match head { Ok() => ..., Err() => ... }`
|
||||
self.expr_match(sp, head, vec![ok_arm, err_arm])
|
||||
}
|
||||
|
||||
|
|
@ -972,7 +969,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME unused self
|
||||
// FIXME: unused `self`
|
||||
fn fn_decl(&self, inputs: Vec<ast::Arg>, output: ast::FunctionRetTy) -> P<ast::FnDecl> {
|
||||
P(ast::FnDecl {
|
||||
inputs,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@
|
|||
use AttributeType::*;
|
||||
use AttributeGate::*;
|
||||
|
||||
use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd};
|
||||
use crate::ast::{
|
||||
self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
|
||||
PatKind, RangeEnd,
|
||||
};
|
||||
use crate::attr;
|
||||
use crate::early_buffered_lints::BufferedEarlyLintId;
|
||||
use crate::source_map::Spanned;
|
||||
|
|
@ -554,6 +557,9 @@ declare_features! (
|
|||
// Allows using C-variadics.
|
||||
(active, c_variadic, "1.34.0", Some(44930), None),
|
||||
|
||||
// Allows the user of associated type bounds.
|
||||
(active, associated_type_bounds, "1.34.0", Some(52662), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
@ -1917,7 +1923,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
self.builtin_attributes.get(&ident.name).map(|a| *a)
|
||||
});
|
||||
|
||||
// check for gated attributes
|
||||
// Check for gated attributes.
|
||||
self.context.check_attribute(attr, attr_info, false);
|
||||
|
||||
if attr.check_name(sym::doc) {
|
||||
|
|
@ -2115,7 +2121,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
|
||||
if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
|
||||
if let ast::TyKind::Never = output_ty.node {
|
||||
// Do nothing
|
||||
// Do nothing.
|
||||
} else {
|
||||
self.visit_ty(output_ty)
|
||||
}
|
||||
|
|
@ -2171,7 +2177,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_expr(self, e);
|
||||
visit::walk_expr(self, e)
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, arm: &'a ast::Arm) {
|
||||
|
|
@ -2220,15 +2226,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
|
||||
}
|
||||
|
||||
visit::walk_fn(self, fn_kind, fn_decl, span);
|
||||
visit::walk_fn(self, fn_kind, fn_decl, span)
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'a GenericParam) {
|
||||
if let GenericParamKind::Const { .. } = param.kind {
|
||||
gate_feature_post!(&self, const_generics, param.ident.span,
|
||||
"const generics are unstable");
|
||||
match param.kind {
|
||||
GenericParamKind::Const { .. } =>
|
||||
gate_feature_post!(&self, const_generics, param.ident.span,
|
||||
"const generics are unstable"),
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_generic_param(self, param);
|
||||
visit::walk_generic_param(self, param)
|
||||
}
|
||||
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
|
||||
match constraint.kind {
|
||||
AssocTyConstraintKind::Bound { .. } =>
|
||||
gate_feature_post!(&self, associated_type_bounds, constraint.span,
|
||||
"associated type bounds are unstable"),
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_assoc_ty_constraint(self, constraint)
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
|
||||
|
|
@ -2266,7 +2284,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_trait_item(self, ti);
|
||||
visit::walk_trait_item(self, ti)
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
|
||||
|
|
@ -2298,7 +2316,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_impl_item(self, ii);
|
||||
visit::walk_impl_item(self, ii)
|
||||
}
|
||||
|
||||
fn visit_vis(&mut self, vis: &'a ast::Visibility) {
|
||||
|
|
@ -2306,7 +2324,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
gate_feature_post!(&self, crate_visibility_modifier, vis.span,
|
||||
"`crate` visibility modifier is experimental");
|
||||
}
|
||||
visit::walk_vis(self, vis);
|
||||
visit::walk_vis(self, vis)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ pub trait MutVisitor: Sized {
|
|||
noop_visit_lifetime(l, self);
|
||||
}
|
||||
|
||||
fn visit_ty_binding(&mut self, t: &mut TypeBinding) {
|
||||
noop_visit_ty_binding(t, self);
|
||||
fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
|
||||
noop_visit_ty_constraint(t, self);
|
||||
}
|
||||
|
||||
fn visit_mod(&mut self, m: &mut Mod) {
|
||||
|
|
@ -400,11 +400,20 @@ pub fn noop_visit_guard<T: MutVisitor>(g: &mut Guard, vis: &mut T) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_ty_binding<T: MutVisitor>(TypeBinding { id, ident, ty, span }: &mut TypeBinding,
|
||||
vis: &mut T) {
|
||||
pub fn noop_visit_ty_constraint<T: MutVisitor>(
|
||||
AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
|
||||
vis: &mut T
|
||||
) {
|
||||
vis.visit_id(id);
|
||||
vis.visit_ident(ident);
|
||||
vis.visit_ty(ty);
|
||||
match kind {
|
||||
AssocTyConstraintKind::Equality { ref mut ty } => {
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
AssocTyConstraintKind::Bound { ref mut bounds } => {
|
||||
visit_bounds(bounds, vis);
|
||||
}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -499,9 +508,9 @@ pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T)
|
|||
|
||||
pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(data: &mut AngleBracketedArgs,
|
||||
vis: &mut T) {
|
||||
let AngleBracketedArgs { args, bindings, span } = data;
|
||||
let AngleBracketedArgs { args, constraints, span } = data;
|
||||
visit_vec(args, |arg| vis.visit_generic_arg(arg));
|
||||
visit_vec(bindings, |binding| vis.visit_ty_binding(binding));
|
||||
visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use crate::ast::{VariantData, StructField};
|
|||
use crate::ast::StrStyle;
|
||||
use crate::ast::SelfKind;
|
||||
use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax};
|
||||
use crate::ast::{Ty, TyKind, TypeBinding, GenericBounds};
|
||||
use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds};
|
||||
use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar};
|
||||
use crate::ast::{UseTree, UseTreeKind};
|
||||
use crate::ast::{BinOpKind, UnOp};
|
||||
|
|
@ -191,24 +191,24 @@ enum PrevTokenKind {
|
|||
Other,
|
||||
}
|
||||
|
||||
/* ident is handled by common.rs */
|
||||
// NOTE: `Ident`s are handled by `common.rs`.
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Parser<'a> {
|
||||
pub sess: &'a ParseSess,
|
||||
/// the current token:
|
||||
/// The current token.
|
||||
pub token: token::Token,
|
||||
/// the span of the current token:
|
||||
/// The span of the current token.
|
||||
pub span: Span,
|
||||
/// the span of the previous token:
|
||||
meta_var_span: Option<Span>,
|
||||
/// The span of the previous token.
|
||||
pub prev_span: Span,
|
||||
/// the previous token kind
|
||||
/// The kind of the previous troken.
|
||||
prev_token_kind: PrevTokenKind,
|
||||
restrictions: Restrictions,
|
||||
/// Used to determine the path to externally loaded source files
|
||||
/// Used to determine the path to externally loaded source files.
|
||||
crate directory: Directory<'a>,
|
||||
/// Whether to parse sub-modules in other files.
|
||||
/// `true` to parse sub-modules in other files.
|
||||
pub recurse_into_file_modules: bool,
|
||||
/// Name of the root module this parser originated from. If `None`, then the
|
||||
/// name is not known. This does not change while the parser is descending
|
||||
|
|
@ -217,7 +217,7 @@ pub struct Parser<'a> {
|
|||
crate expected_tokens: Vec<TokenType>,
|
||||
crate token_cursor: TokenCursor,
|
||||
desugar_doc_comments: bool,
|
||||
/// Whether we should configure out of line modules as we parse.
|
||||
/// `true` we should configure out of line modules as we parse.
|
||||
pub cfg_mods: bool,
|
||||
/// This field is used to keep track of how many left angle brackets we have seen. This is
|
||||
/// required in order to detect extra leading left angle brackets (`<` characters) and error
|
||||
|
|
@ -1791,11 +1791,11 @@ impl<'a> Parser<'a> {
|
|||
let lo = self.span;
|
||||
let args = if self.eat_lt() {
|
||||
// `<'a, T, A = U>`
|
||||
let (args, bindings) =
|
||||
let (args, constraints) =
|
||||
self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?;
|
||||
self.expect_gt()?;
|
||||
let span = lo.to(self.prev_span);
|
||||
AngleBracketedArgs { args, bindings, span }.into()
|
||||
AngleBracketedArgs { args, constraints, span }.into()
|
||||
} else {
|
||||
// `(T, U) -> R`
|
||||
self.bump(); // `(`
|
||||
|
|
@ -2680,8 +2680,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// parse a stream of tokens into a list of TokenTree's,
|
||||
// up to EOF.
|
||||
/// Parses a stream of tokens into a list of `TokenTree`s, up to EOF.
|
||||
pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> {
|
||||
let mut tts = Vec::new();
|
||||
while self.token != token::Eof {
|
||||
|
|
@ -5077,7 +5076,7 @@ impl<'a> Parser<'a> {
|
|||
&mut self,
|
||||
style: PathStyle,
|
||||
lo: Span,
|
||||
) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
|
||||
) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
|
||||
// We need to detect whether there are extra leading left angle brackets and produce an
|
||||
// appropriate error and suggestion. This cannot be implemented by looking ahead at
|
||||
// upcoming tokens for a matching `>` character - if there are unmatched `<` tokens
|
||||
|
|
@ -5212,11 +5211,11 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
|
||||
/// possibly including trailing comma.
|
||||
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
|
||||
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
|
||||
let mut args = Vec::new();
|
||||
let mut bindings = Vec::new();
|
||||
let mut misplaced_assoc_ty_bindings: Vec<Span> = Vec::new();
|
||||
let mut assoc_ty_bindings: Vec<Span> = Vec::new();
|
||||
let mut constraints = Vec::new();
|
||||
let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
|
||||
let mut assoc_ty_constraints: Vec<Span> = Vec::new();
|
||||
|
||||
let args_lo = self.span;
|
||||
|
||||
|
|
@ -5224,21 +5223,31 @@ impl<'a> Parser<'a> {
|
|||
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
||||
// Parse lifetime argument.
|
||||
args.push(GenericArg::Lifetime(self.expect_lifetime()));
|
||||
misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
|
||||
} else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
|
||||
// Parse associated type binding.
|
||||
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
|
||||
} else if self.check_ident() && self.look_ahead(1,
|
||||
|t| t == &token::Eq || t == &token::Colon) {
|
||||
// Parse associated type constraint.
|
||||
let lo = self.span;
|
||||
let ident = self.parse_ident()?;
|
||||
self.bump();
|
||||
let ty = self.parse_ty()?;
|
||||
let kind = if self.eat(&token::Eq) {
|
||||
AssocTyConstraintKind::Equality {
|
||||
ty: self.parse_ty()?,
|
||||
}
|
||||
} else if self.eat(&token::Colon) {
|
||||
AssocTyConstraintKind::Bound {
|
||||
bounds: self.parse_generic_bounds(Some(self.prev_span))?,
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
let span = lo.to(self.prev_span);
|
||||
bindings.push(TypeBinding {
|
||||
constraints.push(AssocTyConstraint {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
ident,
|
||||
ty,
|
||||
kind,
|
||||
span,
|
||||
});
|
||||
assoc_ty_bindings.push(span);
|
||||
assoc_ty_constraints.push(span);
|
||||
} else if self.check_const_arg() {
|
||||
// Parse const argument.
|
||||
let expr = if let token::OpenDelim(token::Brace) = self.token {
|
||||
|
|
@ -5262,11 +5271,11 @@ impl<'a> Parser<'a> {
|
|||
value: expr,
|
||||
};
|
||||
args.push(GenericArg::Const(value));
|
||||
misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
|
||||
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
|
||||
} else if self.check_type() {
|
||||
// Parse type argument.
|
||||
args.push(GenericArg::Type(self.parse_ty()?));
|
||||
misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings);
|
||||
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
|
@ -5279,12 +5288,12 @@ impl<'a> Parser<'a> {
|
|||
// FIXME: we would like to report this in ast_validation instead, but we currently do not
|
||||
// preserve ordering of generic parameters with respect to associated type binding, so we
|
||||
// lose that information after parsing.
|
||||
if misplaced_assoc_ty_bindings.len() > 0 {
|
||||
if misplaced_assoc_ty_constraints.len() > 0 {
|
||||
let mut err = self.struct_span_err(
|
||||
args_lo.to(self.prev_span),
|
||||
"associated type bindings must be declared after generic parameters",
|
||||
);
|
||||
for span in misplaced_assoc_ty_bindings {
|
||||
for span in misplaced_assoc_ty_constraints {
|
||||
err.span_label(
|
||||
span,
|
||||
"this associated type binding should be moved after the generic parameters",
|
||||
|
|
@ -5293,7 +5302,7 @@ impl<'a> Parser<'a> {
|
|||
err.emit();
|
||||
}
|
||||
|
||||
Ok((args, bindings))
|
||||
Ok((args, constraints))
|
||||
}
|
||||
|
||||
/// Parses an optional where-clause and places it in `generics`.
|
||||
|
|
@ -5344,9 +5353,10 @@ impl<'a> Parser<'a> {
|
|||
// Parse optional `for<'a, 'b>`.
|
||||
// This `for` is parsed greedily and applies to the whole predicate,
|
||||
// the bounded type can have its own `for` applying only to it.
|
||||
// Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/>
|
||||
// Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/>
|
||||
// Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/>
|
||||
// Examples:
|
||||
// * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
|
||||
// * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
|
||||
// * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
|
||||
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
|
||||
|
||||
// Parse type with mandatory colon and (possibly empty) bounds,
|
||||
|
|
@ -5478,17 +5488,17 @@ impl<'a> Parser<'a> {
|
|||
this.look_ahead(n + 1, |t| t != &token::ModSep)
|
||||
};
|
||||
|
||||
// Parse optional self parameter of a method.
|
||||
// Only a limited set of initial token sequences is considered self parameters, anything
|
||||
// Parse optional `self` parameter of a method.
|
||||
// Only a limited set of initial token sequences is considered `self` parameters; anything
|
||||
// else is parsed as a normal function parameter list, so some lookahead is required.
|
||||
let eself_lo = self.span;
|
||||
let (eself, eself_ident, eself_hi) = match self.token {
|
||||
token::BinOp(token::And) => {
|
||||
// &self
|
||||
// &mut self
|
||||
// &'lt self
|
||||
// &'lt mut self
|
||||
// ¬_self
|
||||
// `&self`
|
||||
// `&mut self`
|
||||
// `&'lt self`
|
||||
// `&'lt mut self`
|
||||
// `¬_self`
|
||||
(if isolated_self(self, 1) {
|
||||
self.bump();
|
||||
SelfKind::Region(None, Mutability::Immutable)
|
||||
|
|
@ -5514,10 +5524,10 @@ impl<'a> Parser<'a> {
|
|||
}, expect_ident(self), self.prev_span)
|
||||
}
|
||||
token::BinOp(token::Star) => {
|
||||
// *self
|
||||
// *const self
|
||||
// *mut self
|
||||
// *not_self
|
||||
// `*self`
|
||||
// `*const self`
|
||||
// `*mut self`
|
||||
// `*not_self`
|
||||
// Emit special error for `self` cases.
|
||||
let msg = "cannot pass `self` by raw pointer";
|
||||
(if isolated_self(self, 1) {
|
||||
|
|
@ -5540,8 +5550,8 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
token::Ident(..) => {
|
||||
if isolated_self(self, 0) {
|
||||
// self
|
||||
// self: TYPE
|
||||
// `self`
|
||||
// `self: TYPE`
|
||||
let eself_ident = expect_ident(self);
|
||||
let eself_hi = self.prev_span;
|
||||
(if self.eat(&token::Colon) {
|
||||
|
|
@ -5552,8 +5562,8 @@ impl<'a> Parser<'a> {
|
|||
}, eself_ident, eself_hi)
|
||||
} else if self.token.is_keyword(kw::Mut) &&
|
||||
isolated_self(self, 1) {
|
||||
// mut self
|
||||
// mut self: TYPE
|
||||
// `mut self`
|
||||
// `mut self: TYPE`
|
||||
self.bump();
|
||||
let eself_ident = expect_ident(self);
|
||||
let eself_hi = self.prev_span;
|
||||
|
|
@ -5580,7 +5590,7 @@ impl<'a> Parser<'a> {
|
|||
{
|
||||
self.expect(&token::OpenDelim(token::Paren))?;
|
||||
|
||||
// Parse optional self argument
|
||||
// Parse optional self argument.
|
||||
let self_arg = self.parse_self_arg()?;
|
||||
|
||||
// Parse the rest of the function parameter list.
|
||||
|
|
|
|||
|
|
@ -1715,7 +1715,7 @@ impl<'a> State<'a> {
|
|||
match els {
|
||||
Some(_else) => {
|
||||
match _else.node {
|
||||
// "another else-if"
|
||||
// Another `else if` block.
|
||||
ast::ExprKind::If(ref i, ref then, ref e) => {
|
||||
self.cbox(INDENT_UNIT - 1)?;
|
||||
self.ibox(0)?;
|
||||
|
|
@ -1725,7 +1725,7 @@ impl<'a> State<'a> {
|
|||
self.print_block(then)?;
|
||||
self.print_else(e.as_ref().map(|e| &**e))
|
||||
}
|
||||
// "another else-if-let"
|
||||
// Another `else if let` block.
|
||||
ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
|
||||
self.cbox(INDENT_UNIT - 1)?;
|
||||
self.ibox(0)?;
|
||||
|
|
@ -1738,14 +1738,14 @@ impl<'a> State<'a> {
|
|||
self.print_block(then)?;
|
||||
self.print_else(e.as_ref().map(|e| &**e))
|
||||
}
|
||||
// "final else"
|
||||
// Final `else` block.
|
||||
ast::ExprKind::Block(ref b, _) => {
|
||||
self.cbox(INDENT_UNIT - 1)?;
|
||||
self.ibox(0)?;
|
||||
self.s.word(" else ")?;
|
||||
self.print_block(b)
|
||||
}
|
||||
// BLEAH, constraints would be great here
|
||||
// Constraints would be great here!
|
||||
_ => {
|
||||
panic!("print_if saw if with weird alternative");
|
||||
}
|
||||
|
|
@ -2450,14 +2450,21 @@ impl<'a> State<'a> {
|
|||
|
||||
let mut comma = data.args.len() != 0;
|
||||
|
||||
for binding in data.bindings.iter() {
|
||||
for constraint in data.constraints.iter() {
|
||||
if comma {
|
||||
self.word_space(",")?
|
||||
}
|
||||
self.print_ident(binding.ident)?;
|
||||
self.print_ident(constraint.ident)?;
|
||||
self.s.space()?;
|
||||
self.word_space("=")?;
|
||||
self.print_type(&binding.ty)?;
|
||||
match constraint.kind {
|
||||
ast::AssocTyConstraintKind::Equality { ref ty } => {
|
||||
self.word_space("=")?;
|
||||
self.print_type(ty)?;
|
||||
}
|
||||
ast::AssocTyConstraintKind::Bound { ref bounds } => {
|
||||
self.print_type_bounds(":", &*bounds)?;
|
||||
}
|
||||
}
|
||||
comma = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ impl<T: 'static> P<T> {
|
|||
{
|
||||
f(*self.ptr)
|
||||
}
|
||||
/// Equivalent to and_then(|x| x)
|
||||
|
||||
/// Equivalent to `and_then(|x| x)`.
|
||||
pub fn into_inner(self) -> T {
|
||||
*self.ptr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,9 +131,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
|||
self.count += 1;
|
||||
walk_generic_args(self, path_span, generic_args)
|
||||
}
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
|
||||
self.count += 1;
|
||||
walk_assoc_type_binding(self, type_binding)
|
||||
walk_assoc_ty_constraint(self, constraint)
|
||||
}
|
||||
fn visit_attribute(&mut self, _attr: &Attribute) {
|
||||
self.count += 1;
|
||||
|
|
|
|||
|
|
@ -139,8 +139,8 @@ pub trait Visitor<'ast>: Sized {
|
|||
GenericArg::Const(ct) => self.visit_anon_const(ct),
|
||||
}
|
||||
}
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &'ast TypeBinding) {
|
||||
walk_assoc_type_binding(self, type_binding)
|
||||
fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
|
||||
walk_assoc_ty_constraint(self, constraint)
|
||||
}
|
||||
fn visit_attribute(&mut self, attr: &'ast Attribute) {
|
||||
walk_attribute(self, attr)
|
||||
|
|
@ -404,7 +404,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
|
|||
match *generic_args {
|
||||
GenericArgs::AngleBracketed(ref data) => {
|
||||
walk_list!(visitor, visit_generic_arg, &data.args);
|
||||
walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
|
||||
walk_list!(visitor, visit_assoc_ty_constraint, &data.constraints);
|
||||
}
|
||||
GenericArgs::Parenthesized(ref data) => {
|
||||
walk_list!(visitor, visit_ty, &data.inputs);
|
||||
|
|
@ -413,10 +413,17 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn walk_assoc_type_binding<'a, V: Visitor<'a>>(visitor: &mut V,
|
||||
type_binding: &'a TypeBinding) {
|
||||
visitor.visit_ident(type_binding.ident);
|
||||
visitor.visit_ty(&type_binding.ty);
|
||||
pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V,
|
||||
constraint: &'a AssocTyConstraint) {
|
||||
visitor.visit_ident(constraint.ident);
|
||||
match constraint.kind {
|
||||
AssocTyConstraintKind::Equality { ref ty } => {
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
AssocTyConstraintKind::Bound { ref bounds } => {
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
||||
|
|
@ -499,7 +506,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Generi
|
|||
walk_list!(visitor, visit_attribute, param.attrs.iter());
|
||||
walk_list!(visitor, visit_param_bound, ¶m.bounds);
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime => {}
|
||||
GenericParamKind::Lifetime => (),
|
||||
GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
|
||||
GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -922,8 +922,7 @@ impl<'a> MethodDef<'a> {
|
|||
arg_types: Vec<(Ident, P<ast::Ty>)>,
|
||||
body: P<Expr>)
|
||||
-> ast::ImplItem {
|
||||
|
||||
// create the generics that aren't for Self
|
||||
// Create the generics that aren't for `Self`.
|
||||
let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
|
||||
|
||||
let args = {
|
||||
|
|
|
|||
|
|
@ -245,8 +245,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
|||
// First up, make sure we're checking a bare function. If we're not then
|
||||
// we're just not interested in this item.
|
||||
//
|
||||
// If we find one, try to locate a `#[proc_macro_derive]` attribute on
|
||||
// it.
|
||||
// If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
|
||||
let is_fn = match item.node {
|
||||
ast::ItemKind::Fn(..) => true,
|
||||
_ => false,
|
||||
|
|
@ -259,7 +258,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
|||
if let Some(prev_attr) = found_attr {
|
||||
let msg = if attr.path.segments[0].ident.name ==
|
||||
prev_attr.path.segments[0].ident.name {
|
||||
format!("Only one `#[{}]` attribute is allowed on any given function",
|
||||
format!("only one `#[{}]` attribute is allowed on any given function",
|
||||
attr.path)
|
||||
} else {
|
||||
format!("`#[{}]` and `#[{}]` attributes cannot both be applied \
|
||||
|
|
@ -267,7 +266,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
|||
};
|
||||
|
||||
self.handler.struct_span_err(attr.span, &msg)
|
||||
.span_note(prev_attr.span, "Previous attribute here")
|
||||
.span_note(prev_attr.span, "previous attribute here")
|
||||
.emit();
|
||||
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -714,7 +714,7 @@ pub enum CompilerDesugaringKind {
|
|||
/// Desugaring of an `impl Trait` in return type position
|
||||
/// to an `existential type Foo: Trait;` and replacing the
|
||||
/// `impl Trait` with `Foo`.
|
||||
ExistentialReturnType,
|
||||
ExistentialType,
|
||||
Async,
|
||||
Await,
|
||||
ForLoop,
|
||||
|
|
@ -728,7 +728,7 @@ impl CompilerDesugaringKind {
|
|||
CompilerDesugaringKind::Await => "await",
|
||||
CompilerDesugaringKind::QuestionMark => "?",
|
||||
CompilerDesugaringKind::TryBlock => "try block",
|
||||
CompilerDesugaringKind::ExistentialReturnType => "existential type",
|
||||
CompilerDesugaringKind::ExistentialType => "existential type",
|
||||
CompilerDesugaringKind::ForLoop => "for loop",
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ symbols! {
|
|||
arm_target_feature,
|
||||
asm,
|
||||
associated_consts,
|
||||
associated_type_bounds,
|
||||
associated_type_defaults,
|
||||
associated_types,
|
||||
async_await,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
{ "type": "test", "event": "started", "name": "a" }
|
||||
{ "type": "test", "name": "a", "event": "ok" }
|
||||
{ "type": "test", "event": "started", "name": "b" }
|
||||
{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" }
|
||||
{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" }
|
||||
{ "type": "test", "event": "started", "name": "c" }
|
||||
{ "type": "test", "name": "c", "event": "ok" }
|
||||
{ "type": "test", "event": "started", "name": "d" }
|
||||
|
|
|
|||
|
|
@ -1,23 +1,21 @@
|
|||
// ignore-cross-compile
|
||||
|
||||
|
||||
// The general idea of this test is to enumerate all "interesting" expressions and check that
|
||||
// `parse(print(e)) == e` for all `e`. Here's what's interesting, for the purposes of this test:
|
||||
// `parse(print(e)) == e` for all `e`. Here's what's interesting, for the purposes of this test:
|
||||
//
|
||||
// 1. The test focuses on expression nesting, because interactions between different expression
|
||||
// types are harder to test manually than single expression types in isolation.
|
||||
// 1. The test focuses on expression nesting, because interactions between different expression
|
||||
// types are harder to test manually than single expression types in isolation.
|
||||
//
|
||||
// 2. The test only considers expressions of at most two nontrivial nodes. So it will check `x +
|
||||
// x` and `x + (x - x)` but not `(x * x) + (x - x)`. The assumption here is that the correct
|
||||
// handling of an expression might depend on the expression's parent, but doesn't depend on its
|
||||
// siblings or any more distant ancestors.
|
||||
// 2. The test only considers expressions of at most two nontrivial nodes. So it will check `x +
|
||||
// x` and `x + (x - x)` but not `(x * x) + (x - x)`. The assumption here is that the correct
|
||||
// handling of an expression might depend on the expression's parent, but doesn't depend on its
|
||||
// siblings or any more distant ancestors.
|
||||
//
|
||||
// 3. The test only checks certain expression kinds. The assumption is that similar expression
|
||||
// types, such as `if` and `while` or `+` and `-`, will be handled identically in the printer
|
||||
// and parser. So if all combinations of exprs involving `if` work correctly, then combinations
|
||||
// 3. The test only checks certain expression kinds. The assumption is that similar expression
|
||||
// types, such as `if` and `while` or `+` and `-`, will be handled identically in the printer
|
||||
// and parser. So if all combinations of exprs involving `if` work correctly, then combinations
|
||||
// using `while`, `if let`, and so on will likely work as well.
|
||||
|
||||
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_data_structures;
|
||||
|
|
@ -155,9 +153,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
|
|||
}
|
||||
|
||||
|
||||
// Folders for manipulating the placement of `Paren` nodes. See below for why this is needed.
|
||||
// Folders for manipulating the placement of `Paren` nodes. See below for why this is needed.
|
||||
|
||||
/// MutVisitor that removes all `ExprKind::Paren` nodes.
|
||||
/// `MutVisitor` that removes all `ExprKind::Paren` nodes.
|
||||
struct RemoveParens;
|
||||
|
||||
impl MutVisitor for RemoveParens {
|
||||
|
|
@ -171,7 +169,7 @@ impl MutVisitor for RemoveParens {
|
|||
}
|
||||
|
||||
|
||||
/// MutVisitor that inserts `ExprKind::Paren` nodes around every `Expr`.
|
||||
/// `MutVisitor` that inserts `ExprKind::Paren` nodes around every `Expr`.
|
||||
struct AddParens;
|
||||
|
||||
impl MutVisitor for AddParens {
|
||||
|
|
@ -205,8 +203,8 @@ fn run() {
|
|||
|
||||
// We want to know if `parsed` is structurally identical to `e`, ignoring trivial
|
||||
// differences like placement of `Paren`s or the exact ranges of node spans.
|
||||
// Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
|
||||
// everywhere we can, then pretty-print. This should give an unambiguous representation of
|
||||
// Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
|
||||
// everywhere we can, then pretty-print. This should give an unambiguous representation of
|
||||
// each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't
|
||||
// relying on the correctness of the very thing we're testing.
|
||||
RemoveParens.visit_expr(&mut e);
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
|
|||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(record_type::<u32>(3), 42);
|
||||
assert_eq!(record_type::<u32>(3), 42);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ fn check_for_no_backtrace(test: std::process::Output) {
|
|||
let mut it = err.lines();
|
||||
|
||||
assert_eq!(it.next().map(|l| l.starts_with("thread '<unnamed>' panicked at")), Some(true));
|
||||
assert_eq!(it.next(), Some("note: Run with `RUST_BACKTRACE=1` \
|
||||
assert_eq!(it.next(), Some("note: run with `RUST_BACKTRACE=1` \
|
||||
environment variable to display a backtrace."));
|
||||
assert_eq!(it.next().map(|l| l.starts_with("thread 'main' panicked at")), Some(true));
|
||||
assert_eq!(it.next(), None);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(unused_assignments)]
|
||||
|
||||
// Test that duplicate auto trait bounds in trait objects don't create new types.
|
||||
#[allow(unused_assignments)]
|
||||
|
||||
use std::marker::Send as SendAlias;
|
||||
|
||||
// A dummy trait for the non-auto trait.
|
||||
trait Trait {}
|
||||
|
||||
// A dummy struct to implement Trait, Send, and .
|
||||
// A dummy struct to implement `Trait` and `Send`.
|
||||
struct Struct;
|
||||
|
||||
impl Trait for Struct {}
|
||||
|
|
@ -23,12 +24,12 @@ impl dyn Trait + Send + Send {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
// 1. Moving into a variable with more Sends and back.
|
||||
// 1. Moving into a variable with more `Send`s and back.
|
||||
let mut dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
|
||||
let dyn_trait_send_send: Box<dyn Trait + Send + Send> = dyn_trait_send;
|
||||
dyn_trait_send = dyn_trait_send_send;
|
||||
|
||||
// 2. Calling methods with different number of Sends.
|
||||
// 2. Calling methods with different number of `Send`s.
|
||||
let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
|
||||
takes_dyn_trait_send_send(dyn_trait_send);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ stderr:
|
|||
stderr 1
|
||||
stderr 2
|
||||
thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:7:1
|
||||
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
177
src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs
Normal file
177
src/test/ui/associated-type-bounds/auxiliary/fn-aux.rs
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// Traits:
|
||||
|
||||
pub trait Alpha {
|
||||
fn alpha(self) -> usize;
|
||||
}
|
||||
|
||||
pub trait Beta {
|
||||
type Gamma;
|
||||
fn gamma(self) -> Self::Gamma;
|
||||
}
|
||||
|
||||
pub trait Delta {
|
||||
fn delta(self) -> usize;
|
||||
}
|
||||
|
||||
pub trait Epsilon<'a> {
|
||||
type Zeta;
|
||||
fn zeta(&'a self) -> Self::Zeta;
|
||||
|
||||
fn epsilon(&'a self) -> usize;
|
||||
}
|
||||
|
||||
pub trait Eta {
|
||||
fn eta(self) -> usize;
|
||||
}
|
||||
|
||||
// Assertions:
|
||||
|
||||
pub fn assert_alpha<T: Alpha>(x: T) -> usize { x.alpha() }
|
||||
pub fn assert_static<T: 'static>(_: T) -> usize { 24 }
|
||||
pub fn assert_delta<T: Delta>(x: T) -> usize { x.delta() }
|
||||
pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() }
|
||||
pub fn assert_epsilon_forall<T: for<'a> Epsilon<'a>>() {}
|
||||
pub fn assert_forall_epsilon_zeta_satisfies_eta<T>(x: T) -> usize
|
||||
where
|
||||
T: for<'a> Epsilon<'a>,
|
||||
for<'a> <T as Epsilon<'a>>::Zeta: Eta,
|
||||
{
|
||||
x.epsilon() + x.zeta().eta()
|
||||
}
|
||||
|
||||
// Implementations and types:
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct BetaType;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct GammaType;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ZetaType;
|
||||
|
||||
impl Beta for BetaType {
|
||||
type Gamma = GammaType;
|
||||
fn gamma(self) -> Self::Gamma { GammaType }
|
||||
}
|
||||
|
||||
impl<'a> Beta for &'a BetaType {
|
||||
type Gamma = GammaType;
|
||||
fn gamma(self) -> Self::Gamma { GammaType }
|
||||
}
|
||||
|
||||
impl Beta for GammaType {
|
||||
type Gamma = Self;
|
||||
fn gamma(self) -> Self::Gamma { self }
|
||||
}
|
||||
|
||||
impl Alpha for GammaType {
|
||||
fn alpha(self) -> usize { 42 }
|
||||
}
|
||||
|
||||
impl Delta for GammaType {
|
||||
fn delta(self) -> usize { 1337 }
|
||||
}
|
||||
|
||||
impl<'a> Epsilon<'a> for GammaType {
|
||||
type Zeta = ZetaType;
|
||||
fn zeta(&'a self) -> Self::Zeta { ZetaType }
|
||||
|
||||
fn epsilon(&'a self) -> usize { 7331 }
|
||||
}
|
||||
|
||||
impl Eta for ZetaType {
|
||||
fn eta(self) -> usize { 7 }
|
||||
}
|
||||
|
||||
// Desugared forms to check against:
|
||||
|
||||
pub fn desugared_bound<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Alpha
|
||||
{
|
||||
let gamma: B::Gamma = beta.gamma();
|
||||
assert_alpha::<B::Gamma>(gamma)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: 'static,
|
||||
{
|
||||
assert_static::<B::Gamma>(beta.gamma())
|
||||
}
|
||||
|
||||
pub fn desugared_bound_multi<B>(beta: B) -> usize
|
||||
where
|
||||
B: Copy + Beta,
|
||||
B::Gamma: Alpha + 'static + Delta,
|
||||
{
|
||||
assert_alpha::<B::Gamma>(beta.gamma()) +
|
||||
assert_static::<B::Gamma>(beta.gamma()) +
|
||||
assert_delta::<B::Gamma>(beta.gamma())
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: 'a + Epsilon<'a>,
|
||||
{
|
||||
assert_epsilon_specific::<B::Gamma>(gamma)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region_forall<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Copy + for<'a> Epsilon<'a>,
|
||||
{
|
||||
assert_epsilon_forall::<B::Gamma>();
|
||||
let g1: B::Gamma = beta.gamma();
|
||||
let g2: B::Gamma = g1;
|
||||
assert_epsilon_specific::<B::Gamma>(&g1) +
|
||||
assert_epsilon_specific::<B::Gamma>(&g2)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region_forall2<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Copy + for<'a> Epsilon<'a>,
|
||||
for<'a> <B::Gamma as Epsilon<'a>>::Zeta: Eta,
|
||||
{
|
||||
let gamma = beta.gamma();
|
||||
assert_forall_epsilon_zeta_satisfies_eta::<B::Gamma>(gamma)
|
||||
}
|
||||
|
||||
pub fn desugared_contraint_region_forall<B>(beta: B) -> usize
|
||||
where
|
||||
for<'a> &'a B: Beta,
|
||||
for<'a> <&'a B as Beta>::Gamma: Alpha,
|
||||
{
|
||||
let g1 = beta.gamma();
|
||||
let g2 = beta.gamma();
|
||||
assert_alpha(g1) + assert_alpha(g2)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_nested<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Copy + Alpha + Beta,
|
||||
<B::Gamma as Beta>::Gamma: Delta,
|
||||
{
|
||||
let go = beta.gamma();
|
||||
let gi = go.gamma();
|
||||
go.alpha() + gi.delta()
|
||||
}
|
||||
|
||||
pub fn desugared() {
|
||||
let beta = BetaType;
|
||||
let gamma = beta.gamma();
|
||||
|
||||
assert_eq!(42, desugared_bound(beta));
|
||||
assert_eq!(24, desugared_bound_region(beta));
|
||||
assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta));
|
||||
assert_eq!(7331, desugared_bound_region_specific::<BetaType>(&gamma));
|
||||
assert_eq!(7331 * 2, desugared_bound_region_forall(beta));
|
||||
assert_eq!(42 + 1337, desugared_bound_nested(beta));
|
||||
}
|
||||
182
src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs
Normal file
182
src/test/ui/associated-type-bounds/auxiliary/fn-dyn-aux.rs
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// Traits:
|
||||
|
||||
pub trait Alpha {
|
||||
fn alpha(self) -> usize;
|
||||
}
|
||||
|
||||
pub trait Beta {
|
||||
type Gamma;
|
||||
fn gamma(&self) -> Self::Gamma;
|
||||
}
|
||||
|
||||
pub trait Delta {
|
||||
fn delta(self) -> usize;
|
||||
}
|
||||
|
||||
pub trait Epsilon<'a> {
|
||||
type Zeta;
|
||||
fn zeta(&'a self) -> Self::Zeta;
|
||||
|
||||
fn epsilon(&'a self) -> usize;
|
||||
}
|
||||
|
||||
pub trait Eta {
|
||||
fn eta(self) -> usize;
|
||||
}
|
||||
|
||||
// Assertions:
|
||||
|
||||
pub fn assert_alpha<T: Alpha>(x: T) -> usize { x.alpha() }
|
||||
pub fn assert_static<T: 'static>(_: T) -> usize { 24 }
|
||||
pub fn assert_delta<T: Delta>(x: T) -> usize { x.delta() }
|
||||
pub fn assert_epsilon_specific<'a, T: 'a + Epsilon<'a>>(x: &'a T) -> usize { x.epsilon() }
|
||||
pub fn assert_epsilon_forall<T: for<'a> Epsilon<'a>>() {}
|
||||
pub fn assert_forall_epsilon_zeta_satisfies_eta<T>(x: T) -> usize
|
||||
where
|
||||
T: for<'a> Epsilon<'a>,
|
||||
for<'a> <T as Epsilon<'a>>::Zeta: Eta,
|
||||
{
|
||||
x.epsilon() + x.zeta().eta()
|
||||
}
|
||||
|
||||
// Implementations and types:
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct BetaType;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct GammaType;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ZetaType;
|
||||
|
||||
impl<T> Beta for &(dyn Beta<Gamma = T> + Send) {
|
||||
type Gamma = T;
|
||||
fn gamma(&self) -> Self::Gamma { (*self).gamma() }
|
||||
}
|
||||
|
||||
impl Beta for BetaType {
|
||||
type Gamma = GammaType;
|
||||
fn gamma(&self) -> Self::Gamma { GammaType }
|
||||
}
|
||||
|
||||
impl<'a> Beta for &'a BetaType {
|
||||
type Gamma = GammaType;
|
||||
fn gamma(&self) -> Self::Gamma { GammaType }
|
||||
}
|
||||
|
||||
impl Beta for GammaType {
|
||||
type Gamma = Self;
|
||||
fn gamma(&self) -> Self::Gamma { Self }
|
||||
}
|
||||
|
||||
impl Alpha for GammaType {
|
||||
fn alpha(self) -> usize { 42 }
|
||||
}
|
||||
|
||||
impl Delta for GammaType {
|
||||
fn delta(self) -> usize { 1337 }
|
||||
}
|
||||
|
||||
impl<'a> Epsilon<'a> for GammaType {
|
||||
type Zeta = ZetaType;
|
||||
fn zeta(&'a self) -> Self::Zeta { ZetaType }
|
||||
|
||||
fn epsilon(&'a self) -> usize { 7331 }
|
||||
}
|
||||
|
||||
impl Eta for ZetaType {
|
||||
fn eta(self) -> usize { 7 }
|
||||
}
|
||||
|
||||
// Desugared forms to check against:
|
||||
|
||||
pub fn desugared_bound<B: ?Sized>(beta: &B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Alpha
|
||||
{
|
||||
let gamma: B::Gamma = beta.gamma();
|
||||
assert_alpha::<B::Gamma>(gamma)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region<B: ?Sized>(beta: &B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: 'static,
|
||||
{
|
||||
assert_static::<B::Gamma>(beta.gamma())
|
||||
}
|
||||
|
||||
pub fn desugared_bound_multi<B: ?Sized>(beta: B) -> usize
|
||||
where
|
||||
B: Copy + Beta,
|
||||
B::Gamma: Alpha + 'static + Delta,
|
||||
{
|
||||
assert_alpha::<B::Gamma>(beta.gamma()) +
|
||||
assert_static::<B::Gamma>(beta.gamma()) +
|
||||
assert_delta::<B::Gamma>(beta.gamma())
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region_specific<'a, B: ?Sized>(gamma: &'a B::Gamma) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: 'a + Epsilon<'a>,
|
||||
{
|
||||
assert_epsilon_specific::<B::Gamma>(gamma)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region_forall<B: ?Sized>(beta: &B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Copy + for<'a> Epsilon<'a>,
|
||||
{
|
||||
assert_epsilon_forall::<B::Gamma>();
|
||||
let g1: B::Gamma = beta.gamma();
|
||||
let g2: B::Gamma = g1;
|
||||
assert_epsilon_specific::<B::Gamma>(&g1) +
|
||||
assert_epsilon_specific::<B::Gamma>(&g2)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_region_forall2<B: ?Sized>(beta: &B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Copy + for<'a> Epsilon<'a>,
|
||||
for<'a> <B::Gamma as Epsilon<'a>>::Zeta: Eta,
|
||||
{
|
||||
let gamma = beta.gamma();
|
||||
assert_forall_epsilon_zeta_satisfies_eta::<B::Gamma>(gamma)
|
||||
}
|
||||
|
||||
pub fn desugared_contraint_region_forall<B: ?Sized>(beta: &B) -> usize
|
||||
where
|
||||
for<'a> &'a B: Beta,
|
||||
for<'a> <&'a B as Beta>::Gamma: Alpha,
|
||||
{
|
||||
let g1 = beta.gamma();
|
||||
let g2 = beta.gamma();
|
||||
assert_alpha(g1) + assert_alpha(g2)
|
||||
}
|
||||
|
||||
pub fn desugared_bound_nested<B: ?Sized>(beta: &B) -> usize
|
||||
where
|
||||
B: Beta,
|
||||
B::Gamma: Copy + Alpha + Beta,
|
||||
<B::Gamma as Beta>::Gamma: Delta,
|
||||
{
|
||||
let go = beta.gamma();
|
||||
let gi = go.gamma();
|
||||
go.alpha() + gi.delta()
|
||||
}
|
||||
|
||||
pub fn desugared() {
|
||||
let beta = BetaType;
|
||||
let gamma = beta.gamma();
|
||||
|
||||
assert_eq!(42, desugared_bound(&beta));
|
||||
assert_eq!(24, desugared_bound_region(&beta));
|
||||
assert_eq!(42 + 24 + 1337, desugared_bound_multi(beta));
|
||||
assert_eq!(7331, desugared_bound_region_specific::<BetaType>(&gamma));
|
||||
assert_eq!(7331 * 2, desugared_bound_region_forall(&beta));
|
||||
assert_eq!(42 + 1337, desugared_bound_nested(&beta));
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// compile-fail
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
|
||||
// This should hopefully be fixed with Chalk.
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::iter::Once;
|
||||
|
||||
trait Lam<Binder> { type App; }
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L1;
|
||||
impl<'a> Lam<&'a u8> for L1 { type App = u8; }
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L2;
|
||||
impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
|
||||
|
||||
trait Case1 {
|
||||
type C: Clone + Iterator<Item:
|
||||
Send + Iterator<Item:
|
||||
for<'a> Lam<&'a u8, App:
|
||||
Debug
|
||||
>
|
||||
> + Sync>;
|
||||
}
|
||||
|
||||
pub struct S1;
|
||||
impl Case1 for S1 {
|
||||
//~^ ERROR `<L1 as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277]
|
||||
type C = Once<Once<L1>>;
|
||||
}
|
||||
|
||||
fn assume_case1<T: Case1>() {
|
||||
//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277]
|
||||
//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator [E0277]
|
||||
//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely [E0277]
|
||||
//~| ERROR `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely [E0277]
|
||||
fn assert_a<_0, A>() where A: Iterator<Item = _0>, _0: Debug {}
|
||||
assert_a::<_, T::A>();
|
||||
|
||||
fn assert_b<_0, B>() where B: Iterator<Item = _0>, _0: 'static {}
|
||||
assert_b::<_, T::B>();
|
||||
|
||||
fn assert_c<_0, _1, _2, C>()
|
||||
where
|
||||
C: Clone + Iterator<Item = _2>,
|
||||
_2: Send + Iterator<Item = _1>,
|
||||
_1: for<'a> Lam<&'a u8, App = _0>,
|
||||
_0: Debug,
|
||||
{}
|
||||
assert_c::<_, _, _, T::C>();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assume_case1(S1);
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
error[E0277]: `<L1 as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:32:6
|
||||
|
|
||||
LL | impl Case1 for S1 {
|
||||
| ^^^^^ `<L1 as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
||||
|
|
||||
= help: the trait `for<'a> std::fmt::Debug` is not implemented for `<L1 as Lam<&'a u8>>::App`
|
||||
|
||||
error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
|
||||
|
|
||||
LL | / fn assume_case1<T: Case1>() {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | assert_c::<_, _, _, T::C>();
|
||||
LL | | }
|
||||
| |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
|
||||
|
|
||||
= help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
|
||||
= help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator` bound
|
||||
|
||||
error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
|
||||
|
|
||||
LL | / fn assume_case1<T: Case1>() {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | assert_c::<_, _, _, T::C>();
|
||||
LL | | }
|
||||
| |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
|
||||
|
|
||||
= help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
|
||||
= help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send` bound
|
||||
note: required by `Case1`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
|
||||
|
|
||||
LL | trait Case1 {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
|
||||
|
|
||||
LL | / fn assume_case1<T: Case1>() {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | assert_c::<_, _, _, T::C>();
|
||||
LL | | }
|
||||
| |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
|
||||
|
|
||||
= help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
|
||||
= help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync` bound
|
||||
note: required by `Case1`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
|
||||
|
|
||||
LL | trait Case1 {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
|
||||
|
|
||||
LL | / fn assume_case1<T: Case1>() {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | | assert_c::<_, _, _, T::C>();
|
||||
LL | | }
|
||||
| |_^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
||||
|
|
||||
= help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App`
|
||||
note: required by `Case1`
|
||||
--> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1
|
||||
|
|
||||
LL | trait Case1 {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::iter::Empty;
|
||||
use std::ops::Range;
|
||||
|
||||
trait Lam<Binder> { type App; }
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L1;
|
||||
impl<'a> Lam<&'a u8> for L1 { type App = u8; }
|
||||
|
||||
#[derive(Clone)]
|
||||
struct L2;
|
||||
impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
|
||||
|
||||
trait Case1 {
|
||||
type A: Iterator<Item: Debug>;
|
||||
|
||||
type B: Iterator<Item: 'static>;
|
||||
}
|
||||
|
||||
pub struct S1;
|
||||
impl Case1 for S1 {
|
||||
type A = Empty<String>;
|
||||
type B = Range<u16>;
|
||||
}
|
||||
|
||||
// Ensure we don't have existential desugaring:
|
||||
|
||||
pub trait Foo { type Out: Baz<Assoc: Default>; }
|
||||
pub trait Baz { type Assoc; }
|
||||
|
||||
#[derive(Default)]
|
||||
struct S2;
|
||||
#[derive(Default)]
|
||||
struct S3;
|
||||
struct S4;
|
||||
struct S5;
|
||||
struct S6;
|
||||
struct S7;
|
||||
|
||||
impl Foo for S6 { type Out = S4; }
|
||||
impl Foo for S7 { type Out = S5; }
|
||||
|
||||
impl Baz for S4 { type Assoc = S2; }
|
||||
impl Baz for S5 { type Assoc = S3; }
|
||||
|
||||
fn main() {}
|
||||
161
src/test/ui/associated-type-bounds/duplicate.rs
Normal file
161
src/test/ui/associated-type-bounds/duplicate.rs
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
// compile-fail
|
||||
// ignore-tidy-linelength
|
||||
// error-pattern:could not find defining uses
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(existential_type)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
use std::iter;
|
||||
|
||||
struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
existential type ETAI4: Iterator<Item: Copy, Item: Send>;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRS1: Iterator<Item: Copy, Item: Send> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRS2: Iterator<Item: Copy, Item: Copy> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRS3: Iterator<Item: 'static, Item: 'static> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
|
||||
//~^ the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified [E0719]
|
||||
|
||||
fn main() {}
|
||||
632
src/test/ui/associated-type-bounds/duplicate.stderr
Normal file
632
src/test/ui/associated-type-bounds/duplicate.stderr
Normal file
|
|
@ -0,0 +1,632 @@
|
|||
warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/duplicate.rs:7:12
|
||||
|
|
||||
LL | #![feature(impl_trait_in_bindings)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:12:36
|
||||
|
|
||||
LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:14:36
|
||||
|
|
||||
LL | struct SI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:16:39
|
||||
|
|
||||
LL | struct SI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:18:45
|
||||
|
|
||||
LL | struct SW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:20:45
|
||||
|
|
||||
LL | struct SW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:22:48
|
||||
|
|
||||
LL | struct SW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:25:34
|
||||
|
|
||||
LL | enum EI1<T: Iterator<Item: Copy, Item: Send>> { V(T) }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:27:34
|
||||
|
|
||||
LL | enum EI2<T: Iterator<Item: Copy, Item: Copy>> { V(T) }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:29:37
|
||||
|
|
||||
LL | enum EI3<T: Iterator<Item: 'static, Item: 'static>> { V(T) }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:31:43
|
||||
|
|
||||
LL | enum EW1<T> where T: Iterator<Item: Copy, Item: Send> { V(T) }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:33:43
|
||||
|
|
||||
LL | enum EW2<T> where T: Iterator<Item: Copy, Item: Copy> { V(T) }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:35:46
|
||||
|
|
||||
LL | enum EW3<T> where T: Iterator<Item: 'static, Item: 'static> { V(T) }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:38:35
|
||||
|
|
||||
LL | union UI1<T: Iterator<Item: Copy, Item: Send>> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:40:35
|
||||
|
|
||||
LL | union UI2<T: Iterator<Item: Copy, Item: Copy>> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:42:38
|
||||
|
|
||||
LL | union UI3<T: Iterator<Item: 'static, Item: 'static>> { f: T }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:44:44
|
||||
|
|
||||
LL | union UW1<T> where T: Iterator<Item: Copy, Item: Send> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:46:44
|
||||
|
|
||||
LL | union UW2<T> where T: Iterator<Item: Copy, Item: Copy> { f: T }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:48:47
|
||||
|
|
||||
LL | union UW3<T> where T: Iterator<Item: 'static, Item: 'static> { f: T }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:51:32
|
||||
|
|
||||
LL | fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:53:32
|
||||
|
|
||||
LL | fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:55:35
|
||||
|
|
||||
LL | fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:57:43
|
||||
|
|
||||
LL | fn FW1<T>() where T: Iterator<Item: Copy, Item: Send> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:59:43
|
||||
|
|
||||
LL | fn FW2<T>() where T: Iterator<Item: Copy, Item: Copy> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:61:46
|
||||
|
|
||||
LL | fn FW3<T>() where T: Iterator<Item: 'static, Item: 'static> {}
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:70:40
|
||||
|
|
||||
LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:72:40
|
||||
|
|
||||
LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:74:43
|
||||
|
|
||||
LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:64:42
|
||||
|
|
||||
LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:66:42
|
||||
|
|
||||
LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:68:45
|
||||
|
|
||||
LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:77:39
|
||||
|
|
||||
LL | const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:79:39
|
||||
|
|
||||
LL | const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:81:42
|
||||
|
|
||||
LL | const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:83:40
|
||||
|
|
||||
LL | static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:85:40
|
||||
|
|
||||
LL | static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:87:43
|
||||
|
|
||||
LL | static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:90:46
|
||||
|
|
||||
LL | fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:92:46
|
||||
|
|
||||
LL | fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:94:49
|
||||
|
|
||||
LL | fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:97:35
|
||||
|
|
||||
LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:99:35
|
||||
|
|
||||
LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:101:38
|
||||
|
|
||||
LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:103:44
|
||||
|
|
||||
LL | type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:105:44
|
||||
|
|
||||
LL | type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:107:47
|
||||
|
|
||||
LL | type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/duplicate.rs:110:1
|
||||
|
|
||||
LL | existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:110:48
|
||||
|
|
||||
LL | existential type ETAI1<T: Iterator<Item: Copy, Item: Send>>: Copy;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/duplicate.rs:112:1
|
||||
|
|
||||
LL | existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:112:48
|
||||
|
|
||||
LL | existential type ETAI2<T: Iterator<Item: Copy, Item: Copy>>: Copy;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/duplicate.rs:114:1
|
||||
|
|
||||
LL | existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:114:51
|
||||
|
|
||||
LL | existential type ETAI3<T: Iterator<Item: 'static, Item: 'static>>: Copy;
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/duplicate.rs:116:1
|
||||
|
|
||||
LL | existential type ETAI4: Iterator<Item: Copy, Item: Send>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:116:46
|
||||
|
|
||||
LL | existential type ETAI4: Iterator<Item: Copy, Item: Send>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/duplicate.rs:118:1
|
||||
|
|
||||
LL | existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:118:46
|
||||
|
|
||||
LL | existential type ETAI5: Iterator<Item: Copy, Item: Copy>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/duplicate.rs:120:1
|
||||
|
|
||||
LL | existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:120:49
|
||||
|
|
||||
LL | existential type ETAI6: Iterator<Item: 'static, Item: 'static>;
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:123:36
|
||||
|
|
||||
LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:125:36
|
||||
|
|
||||
LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:127:39
|
||||
|
|
||||
LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:129:34
|
||||
|
|
||||
LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:131:34
|
||||
|
|
||||
LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:133:37
|
||||
|
|
||||
LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:135:45
|
||||
|
|
||||
LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:137:45
|
||||
|
|
||||
LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:139:48
|
||||
|
|
||||
LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:141:46
|
||||
|
|
||||
LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:143:46
|
||||
|
|
||||
LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:145:49
|
||||
|
|
||||
LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:147:43
|
||||
|
|
||||
LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:149:43
|
||||
|
|
||||
LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:151:46
|
||||
|
|
||||
LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:154:40
|
||||
|
|
||||
LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:156:44
|
||||
|
|
||||
LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
|
||||
| ---------- ^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
|
||||
--> $DIR/duplicate.rs:158:43
|
||||
|
|
||||
LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
|
||||
| ------------- ^^^^^^^^^^^^^ re-bound here
|
||||
| |
|
||||
| `Item` bound here first
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: aborting due to 93 previous errors
|
||||
|
||||
67
src/test/ui/associated-type-bounds/dyn-existential-type.rs
Normal file
67
src/test/ui/associated-type-bounds/dyn-existential-type.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
|
||||
trait Tr2<'a> { fn tr2(self) -> &'a Self; }
|
||||
|
||||
fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
|
||||
fn assert_static<T: 'static>(_: T) {}
|
||||
fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
|
||||
|
||||
struct S1;
|
||||
#[derive(Copy, Clone)]
|
||||
struct S2;
|
||||
impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
|
||||
|
||||
type Et1 = Box<dyn Tr1<As1: Copy>>;
|
||||
fn def_et1() -> Et1 { Box::new(S1) }
|
||||
pub fn use_et1() { assert_copy(def_et1().mk()); }
|
||||
|
||||
type Et2 = Box<dyn Tr1<As1: 'static>>;
|
||||
fn def_et2() -> Et2 { Box::new(S1) }
|
||||
pub fn use_et2() { assert_static(def_et2().mk()); }
|
||||
|
||||
type Et3 = Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>>;
|
||||
fn def_et3() -> Et3 {
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = core::ops::Range<u8>;
|
||||
fn mk(&self) -> Self::As1 { 0..10 }
|
||||
};
|
||||
Box::new(A)
|
||||
}
|
||||
pub fn use_et3() {
|
||||
let _0 = def_et3().mk().clone();
|
||||
let mut s = 0u8;
|
||||
for _1 in _0 {
|
||||
let _2 = _1 + 1u8;
|
||||
s += _2.into();
|
||||
}
|
||||
assert_eq!(s, (0..10).map(|x| x + 1).sum());
|
||||
}
|
||||
|
||||
type Et4 = Box<dyn Tr1<As1: for<'a> Tr2<'a>>>;
|
||||
fn def_et4() -> Et4 {
|
||||
#[derive(Copy, Clone)]
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = A;
|
||||
fn mk(&self) -> A { A }
|
||||
}
|
||||
impl<'a> Tr2<'a> for A {
|
||||
fn tr2(self) -> &'a Self { &A }
|
||||
}
|
||||
Box::new(A)
|
||||
}
|
||||
pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
|
||||
|
||||
fn main() {
|
||||
let _ = use_et1();
|
||||
let _ = use_et2();
|
||||
let _ = use_et3();
|
||||
let _ = use_et4();
|
||||
}
|
||||
69
src/test/ui/associated-type-bounds/dyn-lcsit.rs
Normal file
69
src/test/ui/associated-type-bounds/dyn-lcsit.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
|
||||
trait Tr2<'a> { fn tr2(self) -> &'a Self; }
|
||||
|
||||
fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
|
||||
fn assert_static<T: 'static>(_: T) {}
|
||||
fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct S1;
|
||||
#[derive(Copy, Clone)]
|
||||
struct S2;
|
||||
impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
|
||||
|
||||
const cdef_et1: &dyn Tr1<As1: Copy> = &S1;
|
||||
const sdef_et1: &dyn Tr1<As1: Copy> = &S1;
|
||||
pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); }
|
||||
|
||||
const cdef_et2: &(dyn Tr1<As1: 'static> + Sync) = &S1;
|
||||
static sdef_et2: &(dyn Tr1<As1: 'static> + Sync) = &S1;
|
||||
pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); }
|
||||
|
||||
const cdef_et3: &dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = {
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = core::ops::Range<u8>;
|
||||
fn mk(&self) -> Self::As1 { 0..10 }
|
||||
};
|
||||
&A
|
||||
};
|
||||
pub fn use_et3() {
|
||||
let _0 = cdef_et3.mk().clone();
|
||||
let mut s = 0u8;
|
||||
for _1 in _0 {
|
||||
let _2 = _1 + 1u8;
|
||||
s += _2.into();
|
||||
}
|
||||
assert_eq!(s, (0..10).map(|x| x + 1).sum());
|
||||
}
|
||||
|
||||
const cdef_et4: &(dyn Tr1<As1: for<'a> Tr2<'a>> + Sync) = {
|
||||
#[derive(Copy, Clone)]
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = A;
|
||||
fn mk(&self) -> A { A }
|
||||
}
|
||||
impl<'a> Tr2<'a> for A {
|
||||
fn tr2(self) -> &'a Self { &A }
|
||||
}
|
||||
&A
|
||||
};
|
||||
static sdef_et4: &(dyn Tr1<As1: for<'a> Tr2<'a>> + Sync) = cdef_et4;
|
||||
pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); }
|
||||
|
||||
fn main() {
|
||||
let _ = use_et1();
|
||||
let _ = use_et2();
|
||||
let _ = use_et3();
|
||||
let _ = use_et4();
|
||||
}
|
||||
6
src/test/ui/associated-type-bounds/dyn-lcsit.stderr
Normal file
6
src/test/ui/associated-type-bounds/dyn-lcsit.stderr
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/dyn-lcsit.rs:4:12
|
||||
|
|
||||
LL | #![feature(impl_trait_in_bindings)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
73
src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs
Normal file
73
src/test/ui/associated-type-bounds/dyn-rpit-and-let.rs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// run-pass
|
||||
|
||||
// FIXME: uncomment let binding types below when `impl_trait_in_bindings` feature is fixed.
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
|
||||
trait Tr2<'a> { fn tr2(self) -> &'a Self; }
|
||||
|
||||
fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
|
||||
fn assert_static<T: 'static>(_: T) {}
|
||||
fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
|
||||
|
||||
struct S1;
|
||||
#[derive(Copy, Clone)]
|
||||
struct S2;
|
||||
impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
|
||||
|
||||
fn def_et1() -> Box<dyn Tr1<As1: Copy>> {
|
||||
let x /* : Box<dyn Tr1<As1: Copy>> */ = Box::new(S1);
|
||||
x
|
||||
}
|
||||
pub fn use_et1() { assert_copy(def_et1().mk()); }
|
||||
|
||||
fn def_et2() -> Box<dyn Tr1<As1: Send + 'static>> {
|
||||
let x /* : Box<dyn Tr1<As1: Send + 'static>> */ = Box::new(S1);
|
||||
x
|
||||
}
|
||||
pub fn use_et2() { assert_static(def_et2().mk()); }
|
||||
|
||||
fn def_et3() -> Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>> {
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = core::ops::Range<u8>;
|
||||
fn mk(&self) -> Self::As1 { 0..10 }
|
||||
};
|
||||
let x /* : Box<dyn Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>> */
|
||||
= Box::new(A);
|
||||
x
|
||||
}
|
||||
pub fn use_et3() {
|
||||
let _0 = def_et3().mk().clone();
|
||||
let mut s = 0u8;
|
||||
for _1 in _0 {
|
||||
let _2 = _1 + 1u8;
|
||||
s += _2.into();
|
||||
}
|
||||
assert_eq!(s, (0..10).map(|x| x + 1).sum());
|
||||
}
|
||||
|
||||
fn def_et4() -> Box<dyn Tr1<As1: for<'a> Tr2<'a>>> {
|
||||
#[derive(Copy, Clone)]
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = A;
|
||||
fn mk(&self) -> A { A }
|
||||
}
|
||||
impl<'a> Tr2<'a> for A {
|
||||
fn tr2(self) -> &'a Self { &A }
|
||||
}
|
||||
let x /* : Box<dyn Tr1<As1: for<'a> Tr2<'a>>> */ = Box::new(A);
|
||||
x
|
||||
}
|
||||
pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
|
||||
|
||||
fn main() {
|
||||
let _ = use_et1();
|
||||
let _ = use_et2();
|
||||
let _ = use_et3();
|
||||
let _ = use_et4();
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// compile-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
trait Tr1: Sized { type As1; }
|
||||
trait Tr2<'a>: Sized { type As2; }
|
||||
|
||||
trait ObjTr1 { fn foo() -> Self where Self: Tr1<As1: Copy>; }
|
||||
fn _assert_obj_safe_1(_: Box<dyn ObjTr1>) {}
|
||||
|
||||
trait ObjTr2 { fn foo() -> Self where Self: Tr1<As1: 'static>; }
|
||||
fn _assert_obj_safe_2(_: Box<dyn ObjTr2>) {}
|
||||
|
||||
trait ObjTr3 { fn foo() -> Self where Self: Tr1<As1: Into<u8> + 'static + Copy>; }
|
||||
fn _assert_obj_safe_3(_: Box<dyn ObjTr3>) {}
|
||||
|
||||
trait ObjTr4 { fn foo() -> Self where Self: Tr1<As1: for<'a> Tr2<'a>>; }
|
||||
fn _assert_obj_safe_4(_: Box<dyn ObjTr4>) {}
|
||||
|
||||
trait ObjTr5 { fn foo() -> Self where for<'a> Self: Tr1<As1: Tr2<'a>>; }
|
||||
fn _assert_obj_safe_5(_: Box<dyn ObjTr5>) {}
|
||||
|
||||
trait ObjTr6 { fn foo() -> Self where Self: for<'a> Tr1<As1: Tr2<'a, As2: for<'b> Tr2<'b>>>; }
|
||||
fn _assert_obj_safe_6(_: Box<dyn ObjTr6>) {}
|
||||
|
||||
fn main() {}
|
||||
122
src/test/ui/associated-type-bounds/enum-bounds.rs
Normal file
122
src/test/ui/associated-type-bounds/enum-bounds.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
trait Tr1 { type As1; }
|
||||
trait Tr2 { type As2; }
|
||||
trait Tr3 { type As3; }
|
||||
trait Tr4<'a> { type As4; }
|
||||
trait Tr5 { type As5; }
|
||||
|
||||
impl Tr1 for &str { type As1 = bool; }
|
||||
impl Tr2 for bool { type As2 = u8; }
|
||||
impl Tr3 for u8 { type As3 = fn() -> u8; }
|
||||
impl Tr1 for () { type As1 = (usize,); }
|
||||
impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
|
||||
impl Tr5 for bool { type As5 = u16; }
|
||||
|
||||
enum En1<T: Tr1<As1: Tr2>> {
|
||||
Outest(T),
|
||||
Outer(T::As1),
|
||||
Inner(<T::As1 as Tr2>::As2),
|
||||
}
|
||||
|
||||
fn wrap_en1_1<T>(x: T) -> En1<T> where T: Tr1, T::As1: Tr2 {
|
||||
En1::Outest(x)
|
||||
}
|
||||
|
||||
fn wrap_en1_2<T>(x: T::As1) -> En1<T> where T: Tr1, T::As1: Tr2 {
|
||||
En1::Outer(x)
|
||||
}
|
||||
|
||||
fn wrap_en1_3<T>(x: <T::As1 as Tr2>::As2) -> En1<T> where T: Tr1, T::As1: Tr2 {
|
||||
En1::Inner(x)
|
||||
}
|
||||
|
||||
enum En2<T: Tr1<As1: Tr2<As2: Tr3>>> {
|
||||
V0(T),
|
||||
V1(T::As1),
|
||||
V2(<T::As1 as Tr2>::As2),
|
||||
V3(<<T::As1 as Tr2>::As2 as Tr3>::As3),
|
||||
}
|
||||
|
||||
enum En3<T: Tr1<As1: 'static>> {
|
||||
V0(T),
|
||||
V1(&'static T::As1),
|
||||
}
|
||||
|
||||
enum En4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
|
||||
V0(&'x1 <T::As1 as Tr4<'x1>>::As4),
|
||||
V1(&'x2 <T::As1 as Tr4<'x2>>::As4),
|
||||
}
|
||||
|
||||
enum _En5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
|
||||
_V0(&'x1 <T::As1 as Tr4<'x1>>::As4),
|
||||
_V1(&'x2 <T::As1 as Tr4<'x2>>::As4),
|
||||
}
|
||||
|
||||
enum En6<T>
|
||||
where
|
||||
T: Tr1<As1: Tr2 + 'static + Tr5>,
|
||||
{
|
||||
V0(T),
|
||||
V1(<T::As1 as Tr2>::As2),
|
||||
V2(&'static T::As1),
|
||||
V3(<T::As1 as Tr5>::As5),
|
||||
}
|
||||
|
||||
enum _En7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
|
||||
where
|
||||
T: Tr1<As1: Tr2>,
|
||||
{
|
||||
V0(&'a T),
|
||||
V1(&'b <T::As1 as Tr2>::As2),
|
||||
}
|
||||
|
||||
fn _make_en7<'a, 'b, T>(x: _En7<'a, 'b, T>)
|
||||
where
|
||||
T: Tr1<As1: Tr2>,
|
||||
{
|
||||
match x {
|
||||
_En7::V0(x) => {
|
||||
let _: &'a T = &x;
|
||||
},
|
||||
_En7::V1(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
enum EnSelf<T> where Self: Tr1<As1: Tr2> {
|
||||
V0(T),
|
||||
V1(<Self as Tr1>::As1),
|
||||
V2(<<Self as Tr1>::As1 as Tr2>::As2),
|
||||
}
|
||||
|
||||
impl Tr1 for EnSelf<&'static str> { type As1 = bool; }
|
||||
|
||||
fn main() {
|
||||
if let En1::Outest("foo") = wrap_en1_1::<_>("foo") {} else { panic!() };
|
||||
if let En1::Outer(true) = wrap_en1_2::<&str>(true) {} else { panic!() };
|
||||
if let En1::Inner(24u8) = wrap_en1_3::<&str>(24u8) {} else { panic!() };
|
||||
|
||||
let _ = En2::<_>::V0("151571");
|
||||
let _ = En2::<&str>::V1(false);
|
||||
let _ = En2::<&str>::V2(42u8);
|
||||
let _ = En2::<&str>::V3(|| 12u8);
|
||||
|
||||
let _ = En3::<_>::V0("deadbeef");
|
||||
let _ = En3::<&str>::V1(&true);
|
||||
|
||||
let f1 = (1,);
|
||||
let f2 = (2,);
|
||||
let _ = En4::<()>::V0(&f1.0);
|
||||
let _ = En4::<()>::V1(&f2.0);
|
||||
|
||||
let _ = En6::<_>::V0("bar");
|
||||
let _ = En6::<&str>::V1(24u8);
|
||||
let _ = En6::<&str>::V2(&false);
|
||||
let _ = En6::<&str>::V3(12u16);
|
||||
|
||||
let _ = EnSelf::<_>::V0("foo");
|
||||
let _ = EnSelf::<&'static str>::V1(true);
|
||||
let _ = EnSelf::<&'static str>::V2(24u8);
|
||||
}
|
||||
67
src/test/ui/associated-type-bounds/existential-type.rs
Normal file
67
src/test/ui/associated-type-bounds/existential-type.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(existential_type)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
trait Tr1 { type As1; fn mk(self) -> Self::As1; }
|
||||
trait Tr2<'a> { fn tr2(self) -> &'a Self; }
|
||||
|
||||
fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
|
||||
fn assert_static<T: 'static>(_: T) {}
|
||||
fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
|
||||
|
||||
struct S1;
|
||||
#[derive(Copy, Clone)]
|
||||
struct S2;
|
||||
impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } }
|
||||
|
||||
existential type Et1: Tr1<As1: Copy>;
|
||||
fn def_et1() -> Et1 { S1 }
|
||||
pub fn use_et1() { assert_copy(def_et1().mk()); }
|
||||
|
||||
existential type Et2: Tr1<As1: 'static>;
|
||||
fn def_et2() -> Et2 { S1 }
|
||||
pub fn use_et2() { assert_static(def_et2().mk()); }
|
||||
|
||||
existential type Et3: Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>>;
|
||||
fn def_et3() -> Et3 {
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = core::ops::Range<u8>;
|
||||
fn mk(self) -> Self::As1 { 0..10 }
|
||||
};
|
||||
A
|
||||
}
|
||||
pub fn use_et3() {
|
||||
let _0 = def_et3().mk().clone();
|
||||
let mut s = 0u8;
|
||||
for _1 in _0 {
|
||||
let _2 = _1 + 1u8;
|
||||
s += _2.into();
|
||||
}
|
||||
assert_eq!(s, (0..10).map(|x| x + 1).sum());
|
||||
}
|
||||
|
||||
existential type Et4: Tr1<As1: for<'a> Tr2<'a>>;
|
||||
fn def_et4() -> Et4 {
|
||||
#[derive(Copy, Clone)]
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = A;
|
||||
fn mk(self) -> A { A }
|
||||
}
|
||||
impl<'a> Tr2<'a> for A {
|
||||
fn tr2(self) -> &'a Self { &A }
|
||||
}
|
||||
A
|
||||
}
|
||||
pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
|
||||
|
||||
fn main() {
|
||||
let _ = use_et1();
|
||||
let _ = use_et2();
|
||||
let _ = use_et3();
|
||||
let _ = use_et4();
|
||||
}
|
||||
58
src/test/ui/associated-type-bounds/fn-apit.rs
Normal file
58
src/test/ui/associated-type-bounds/fn-apit.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// run-pass
|
||||
// aux-build:fn-aux.rs
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
extern crate fn_aux;
|
||||
|
||||
use fn_aux::*;
|
||||
|
||||
fn apit_bound(beta: impl Beta<Gamma: Alpha>) -> usize {
|
||||
desugared_bound(beta)
|
||||
}
|
||||
|
||||
fn apit_bound_region(beta: impl Beta<Gamma: 'static>) -> usize {
|
||||
desugared_bound_region(beta)
|
||||
}
|
||||
|
||||
fn apit_bound_multi(
|
||||
beta: impl Copy + Beta<Gamma: Alpha + 'static + Delta>
|
||||
) -> usize {
|
||||
desugared_bound_multi(beta)
|
||||
}
|
||||
|
||||
fn apit_bound_region_forall(
|
||||
beta: impl Beta<Gamma: Copy + for<'a> Epsilon<'a>>
|
||||
) -> usize {
|
||||
desugared_bound_region_forall(beta)
|
||||
}
|
||||
|
||||
fn apit_bound_region_forall2(
|
||||
beta: impl Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>
|
||||
) -> usize {
|
||||
desugared_bound_region_forall2(beta)
|
||||
}
|
||||
|
||||
fn apit_bound_nested(
|
||||
beta: impl Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>
|
||||
) -> usize {
|
||||
desugared_bound_nested(beta)
|
||||
}
|
||||
|
||||
fn apit_bound_nested2(
|
||||
beta: impl Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>
|
||||
) -> usize {
|
||||
desugared_bound_nested(beta)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let beta = BetaType;
|
||||
let _gamma = beta.gamma();
|
||||
|
||||
assert_eq!(42, apit_bound(beta));
|
||||
assert_eq!(24, apit_bound_region(beta));
|
||||
assert_eq!(42 + 24 + 1337, apit_bound_multi(beta));
|
||||
assert_eq!(7331 * 2, apit_bound_region_forall(beta));
|
||||
assert_eq!(42 + 1337, apit_bound_nested(beta));
|
||||
assert_eq!(42 + 1337, apit_bound_nested2(beta));
|
||||
}
|
||||
12
src/test/ui/associated-type-bounds/fn-aux.rs
Normal file
12
src/test/ui/associated-type-bounds/fn-aux.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// run-pass
|
||||
// aux-build:fn-aux.rs
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
extern crate fn_aux;
|
||||
|
||||
use fn_aux::*;
|
||||
|
||||
fn main() {
|
||||
desugared();
|
||||
}
|
||||
60
src/test/ui/associated-type-bounds/fn-dyn-apit.rs
Normal file
60
src/test/ui/associated-type-bounds/fn-dyn-apit.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// run-pass
|
||||
// aux-build:fn-dyn-aux.rs
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
extern crate fn_dyn_aux;
|
||||
|
||||
use fn_dyn_aux::*;
|
||||
|
||||
// ATB, APIT (dyn trait):
|
||||
|
||||
fn dyn_apit_bound(beta: &dyn Beta<Gamma: Alpha>) -> usize {
|
||||
desugared_bound(beta)
|
||||
}
|
||||
|
||||
fn dyn_apit_bound_region(beta: &dyn Beta<Gamma: 'static>) -> usize {
|
||||
desugared_bound_region(beta)
|
||||
}
|
||||
|
||||
fn dyn_apit_bound_multi(
|
||||
beta: &(dyn Beta<Gamma: Alpha + 'static + Delta> + Send)
|
||||
) -> usize {
|
||||
desugared_bound_multi(beta)
|
||||
}
|
||||
|
||||
fn dyn_apit_bound_region_forall(
|
||||
beta: &dyn Beta<Gamma: Copy + for<'a> Epsilon<'a>>
|
||||
) -> usize {
|
||||
desugared_bound_region_forall(beta)
|
||||
}
|
||||
|
||||
fn dyn_apit_bound_region_forall2(
|
||||
beta: &dyn Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>
|
||||
) -> usize {
|
||||
desugared_bound_region_forall2(beta)
|
||||
}
|
||||
|
||||
fn dyn_apit_bound_nested(
|
||||
beta: &dyn Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>
|
||||
) -> usize {
|
||||
desugared_bound_nested(beta)
|
||||
}
|
||||
|
||||
fn dyn_apit_bound_nested2(
|
||||
beta: &dyn Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>
|
||||
) -> usize {
|
||||
desugared_bound_nested(beta)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let beta = BetaType;
|
||||
let _gamma = beta.gamma();
|
||||
|
||||
assert_eq!(42, dyn_apit_bound(&beta));
|
||||
assert_eq!(24, dyn_apit_bound_region(&beta));
|
||||
assert_eq!(42 + 24 + 1337, dyn_apit_bound_multi(&beta));
|
||||
assert_eq!(7331 * 2, dyn_apit_bound_region_forall(&beta));
|
||||
assert_eq!(42 + 1337, dyn_apit_bound_nested(&beta));
|
||||
assert_eq!(42 + 1337, dyn_apit_bound_nested2(&beta));
|
||||
}
|
||||
62
src/test/ui/associated-type-bounds/fn-inline.rs
Normal file
62
src/test/ui/associated-type-bounds/fn-inline.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// run-pass
|
||||
// aux-build:fn-aux.rs
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
extern crate fn_aux;
|
||||
|
||||
use fn_aux::*;
|
||||
|
||||
// ATB, Type parameters, Inline bounds:
|
||||
|
||||
fn inline_bound<B: Beta<Gamma: Alpha>>(beta: B) -> usize {
|
||||
desugared_bound(beta)
|
||||
}
|
||||
|
||||
fn inline_bound_region<B: Beta<Gamma: 'static>>(beta: B) -> usize {
|
||||
desugared_bound_region(beta)
|
||||
}
|
||||
|
||||
fn inline_bound_multi<B: Copy + Beta<Gamma: Alpha + 'static + Delta>>(
|
||||
beta: B
|
||||
) -> usize {
|
||||
desugared_bound_multi(beta)
|
||||
}
|
||||
|
||||
fn inline_bound_region_specific<'a, B: Beta<Gamma: 'a + Epsilon<'a>>>(
|
||||
gamma: &'a B::Gamma
|
||||
) -> usize {
|
||||
desugared_bound_region_specific::<B>(gamma)
|
||||
}
|
||||
|
||||
fn inline_bound_region_forall<B: Beta<Gamma: Copy + for<'a> Epsilon<'a>>>(
|
||||
beta: B
|
||||
) -> usize {
|
||||
desugared_bound_region_forall(beta)
|
||||
}
|
||||
|
||||
fn inline_bound_region_forall2<B: Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>>(
|
||||
beta: B
|
||||
) -> usize {
|
||||
desugared_bound_region_forall2(beta)
|
||||
}
|
||||
|
||||
fn inline_bound_nested<B: Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>>(
|
||||
beta: B
|
||||
) -> usize {
|
||||
desugared_bound_nested(beta)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let beta = BetaType;
|
||||
let gamma = beta.gamma();
|
||||
|
||||
assert_eq!(42, inline_bound(beta));
|
||||
assert_eq!(24, inline_bound_region(beta));
|
||||
assert_eq!(42 + 24 + 1337, inline_bound_multi(beta));
|
||||
assert_eq!(7331, inline_bound_region_specific::<BetaType>(&gamma));
|
||||
assert_eq!(7331 * 2, inline_bound_region_forall(beta));
|
||||
// FIXME: requires lazy normalization.
|
||||
// assert_eq!(7331 * 2, inline_bound_region_forall2(beta));
|
||||
assert_eq!(42 + 1337, inline_bound_nested(beta));
|
||||
}
|
||||
78
src/test/ui/associated-type-bounds/fn-where.rs
Normal file
78
src/test/ui/associated-type-bounds/fn-where.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// run-pass
|
||||
// aux-build:fn-aux.rs
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
extern crate fn_aux;
|
||||
|
||||
use fn_aux::*;
|
||||
|
||||
// ATB, Type parameters, Where-clauses:
|
||||
|
||||
fn where_bound<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta<Gamma: Alpha>
|
||||
{
|
||||
desugared_bound(beta)
|
||||
}
|
||||
|
||||
fn where_bound_region<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta<Gamma: 'static>
|
||||
{
|
||||
desugared_bound_region(beta)
|
||||
}
|
||||
|
||||
fn where_bound_multi<B>(beta: B) -> usize
|
||||
where
|
||||
B: Copy + Beta<Gamma: Alpha + 'static + Delta>,
|
||||
{
|
||||
desugared_bound_multi(beta)
|
||||
}
|
||||
|
||||
fn where_bound_region_specific<'a, B>(gamma: &'a B::Gamma) -> usize
|
||||
where
|
||||
B: Beta<Gamma: 'a + Epsilon<'a>>,
|
||||
{
|
||||
desugared_bound_region_specific::<B>(gamma)
|
||||
}
|
||||
|
||||
fn where_bound_region_forall<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta<Gamma: Copy + for<'a> Epsilon<'a>>,
|
||||
{
|
||||
desugared_bound_region_forall(beta)
|
||||
}
|
||||
|
||||
fn where_bound_region_forall2<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>,
|
||||
{
|
||||
desugared_bound_region_forall2(beta)
|
||||
}
|
||||
|
||||
fn where_contraint_region_forall<B>(beta: B) -> usize
|
||||
where
|
||||
for<'a> &'a B: Beta<Gamma: Alpha>,
|
||||
{
|
||||
desugared_contraint_region_forall(beta)
|
||||
}
|
||||
|
||||
fn where_bound_nested<B>(beta: B) -> usize
|
||||
where
|
||||
B: Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>,
|
||||
{
|
||||
desugared_bound_nested(beta)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let beta = BetaType;
|
||||
let gamma = beta.gamma();
|
||||
|
||||
assert_eq!(42, where_bound(beta));
|
||||
assert_eq!(24, where_bound_region(beta));
|
||||
assert_eq!(42 + 24 + 1337, where_bound_multi(beta));
|
||||
assert_eq!(7331, where_bound_region_specific::<BetaType>(&gamma));
|
||||
assert_eq!(7331 * 2, where_bound_region_forall::<BetaType>(beta));
|
||||
assert_eq!(42 + 1337, where_bound_nested::<BetaType>(beta));
|
||||
}
|
||||
64
src/test/ui/associated-type-bounds/fn-wrap-apit.rs
Normal file
64
src/test/ui/associated-type-bounds/fn-wrap-apit.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// run-pass
|
||||
// aux-build:fn-aux.rs
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
extern crate fn_aux;
|
||||
|
||||
use fn_aux::*;
|
||||
|
||||
// ATB, APIT + Wrap:
|
||||
|
||||
struct Wrap<T>(T);
|
||||
|
||||
fn wrap_apit_bound(beta: Wrap<impl Beta<Gamma: Alpha>>) -> usize {
|
||||
desugared_bound(beta.0)
|
||||
}
|
||||
|
||||
fn wrap_apit_bound_region(beta: Wrap<impl Beta<Gamma: 'static>>) -> usize {
|
||||
desugared_bound_region(beta.0)
|
||||
}
|
||||
|
||||
fn wrap_apit_bound_multi(
|
||||
beta: Wrap<impl Copy + Beta<Gamma: Alpha + 'static + Delta>>
|
||||
) -> usize {
|
||||
desugared_bound_multi(beta.0)
|
||||
}
|
||||
|
||||
fn wrap_apit_bound_region_forall(
|
||||
beta: Wrap<impl Beta<Gamma: Copy + for<'a> Epsilon<'a>>>
|
||||
) -> usize {
|
||||
desugared_bound_region_forall(beta.0)
|
||||
}
|
||||
|
||||
fn wrap_apit_bound_region_forall2(
|
||||
beta: Wrap<impl Beta<Gamma: Copy + for<'a> Epsilon<'a, Zeta: Eta>>>
|
||||
) -> usize {
|
||||
desugared_bound_region_forall2(beta.0)
|
||||
}
|
||||
|
||||
fn wrap_apit_bound_nested(
|
||||
beta: Wrap<impl Beta<Gamma: Copy + Alpha + Beta<Gamma: Delta>>>
|
||||
) -> usize {
|
||||
desugared_bound_nested(beta.0)
|
||||
}
|
||||
|
||||
fn wrap_apit_bound_nested2(
|
||||
beta: Wrap<impl Beta<Gamma = impl Copy + Alpha + Beta<Gamma: Delta>>>
|
||||
) -> usize {
|
||||
desugared_bound_nested(beta.0)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let beta = BetaType;
|
||||
let _gamma = beta.gamma();
|
||||
|
||||
assert_eq!(42, wrap_apit_bound(Wrap(beta)));
|
||||
assert_eq!(24, wrap_apit_bound_region(Wrap(beta)));
|
||||
assert_eq!(42 + 24 + 1337, wrap_apit_bound_multi(Wrap(beta)));
|
||||
assert_eq!(7331 * 2, wrap_apit_bound_region_forall(Wrap(beta)));
|
||||
// FIXME: requires lazy normalization.
|
||||
// assert_eq!(7331 * 2, wrap_apit_bound_region_forall2(Wrap(beta)));
|
||||
assert_eq!(42 + 1337, wrap_apit_bound_nested(Wrap(beta)));
|
||||
assert_eq!(42 + 1337, wrap_apit_bound_nested2(Wrap(beta)));
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/implied-region-constraints.rs:19:56
|
||||
|
|
||||
LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
|
||||
| ^^^^^ type annotation requires that `'a` must outlive `'b`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/implied-region-constraints.rs:40:64
|
||||
|
|
||||
LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
|
||||
| ^^^^^ type annotation requires that `'a` must outlive `'b`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// compile-fail
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
trait Tr1 { type As1; }
|
||||
trait Tr2 { type As2; }
|
||||
|
||||
struct St<'a, 'b, T: Tr1<As1: Tr2>> { // `T: 'b` is *not* implied!
|
||||
f0: &'a T, // `T: 'a` is implied.
|
||||
f1: &'b <T::As1 as Tr2>::As2, // `<T::As1 as Tr2>::As2: 'a` is implied.
|
||||
}
|
||||
|
||||
fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
|
||||
where
|
||||
T: Tr1,
|
||||
T::As1: Tr2,
|
||||
{
|
||||
// This should fail because `T: 'b` is not implied from `WF(St<'a, 'b, T>)`.
|
||||
let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
|
||||
//~^ ERROR lifetime mismatch [E0623]
|
||||
}
|
||||
|
||||
enum En7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
|
||||
where
|
||||
T: Tr1,
|
||||
T::As1: Tr2,
|
||||
{
|
||||
V0(&'a T),
|
||||
V1(&'b <T::As1 as Tr2>::As2),
|
||||
}
|
||||
|
||||
fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
|
||||
where
|
||||
T: Tr1,
|
||||
T::As1: Tr2,
|
||||
{
|
||||
match x {
|
||||
En7::V0(x) => {
|
||||
// Also fails for the same reason as above:
|
||||
let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
|
||||
//~^ ERROR lifetime mismatch [E0623]
|
||||
},
|
||||
En7::V1(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error[E0623]: lifetime mismatch
|
||||
--> $DIR/implied-region-constraints.rs:19:64
|
||||
|
|
||||
LL | fn _bad_st<'a, 'b, T>(x: St<'a, 'b, T>)
|
||||
| ------------- this type is declared with multiple lifetimes...
|
||||
...
|
||||
LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x.f0;
|
||||
| ^^^^^ ...but data with one lifetime flows into the other here
|
||||
|
||||
error[E0623]: lifetime mismatch
|
||||
--> $DIR/implied-region-constraints.rs:40:72
|
||||
|
|
||||
LL | fn _bad_en7<'a, 'b, T>(x: En7<'a, 'b, T>)
|
||||
| -------------- this type is declared with multiple lifetimes...
|
||||
...
|
||||
LL | let _failure_proves_not_implied_outlives_region_b: &'b T = &x;
|
||||
| ^^ ...but data with one lifetime flows into the other here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
36
src/test/ui/associated-type-bounds/inside-adt.rs
Normal file
36
src/test/ui/associated-type-bounds/inside-adt.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// compile-fail
|
||||
// ignore-tidy-linelength
|
||||
// error-pattern:could not find defining uses
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
struct S1 { f: dyn Iterator<Item: Copy> }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
struct S2 { f: Box<dyn Iterator<Item: Copy>> }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
struct S3 { f: dyn Iterator<Item: 'static> }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
|
||||
enum E1 { V(dyn Iterator<Item: Copy>) }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
enum E3 { V(dyn Iterator<Item: 'static>) }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
|
||||
union U1 { f: dyn Iterator<Item: Copy> }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
union U2 { f: Box<dyn Iterator<Item: Copy>> }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
union U3 { f: dyn Iterator<Item: 'static> }
|
||||
//~^ associated type bounds are not allowed within structs, enums, or unions
|
||||
//~| the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified [E0191]
|
||||
79
src/test/ui/associated-type-bounds/inside-adt.stderr
Normal file
79
src/test/ui/associated-type-bounds/inside-adt.stderr
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:8:29
|
||||
|
|
||||
LL | struct S1 { f: dyn Iterator<Item: Copy> }
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:11:33
|
||||
|
|
||||
LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> }
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:14:29
|
||||
|
|
||||
LL | struct S3 { f: dyn Iterator<Item: 'static> }
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:18:26
|
||||
|
|
||||
LL | enum E1 { V(dyn Iterator<Item: Copy>) }
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:21:30
|
||||
|
|
||||
LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:24:26
|
||||
|
|
||||
LL | enum E3 { V(dyn Iterator<Item: 'static>) }
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:28:28
|
||||
|
|
||||
LL | union U1 { f: dyn Iterator<Item: Copy> }
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:31:32
|
||||
|
|
||||
LL | union U2 { f: Box<dyn Iterator<Item: Copy>> }
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: associated type bounds are not allowed within structs, enums, or unions
|
||||
--> $DIR/inside-adt.rs:34:28
|
||||
|
|
||||
LL | union U3 { f: dyn Iterator<Item: 'static> }
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0601]: `main` function not found in crate `inside_adt`
|
||||
|
|
||||
= note: consider adding a `main` function to `$DIR/inside-adt.rs`
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: could not find defining uses
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0601`.
|
||||
78
src/test/ui/associated-type-bounds/lcsit.rs
Normal file
78
src/test/ui/associated-type-bounds/lcsit.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(impl_trait_in_bindings)]
|
||||
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
trait Tr1 { type As1; fn mk(&self) -> Self::As1; }
|
||||
trait Tr2<'a> { fn tr2(self) -> &'a Self; }
|
||||
|
||||
fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
|
||||
fn assert_static<T: 'static>(_: T) {}
|
||||
fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct S1;
|
||||
#[derive(Copy, Clone)]
|
||||
struct S2;
|
||||
impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } }
|
||||
|
||||
const cdef_et1: impl Copy + Tr1<As1: Copy> = {
|
||||
let x: impl Copy + Tr1<As1: Copy> = S1;
|
||||
x
|
||||
};
|
||||
static sdef_et1: impl Copy + Tr1<As1: Copy> = cdef_et1;
|
||||
pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); }
|
||||
|
||||
const cdef_et2: impl Tr1<As1: 'static> = {
|
||||
let x: impl Tr1<As1: 'static> = S1;
|
||||
x
|
||||
};
|
||||
static sdef_et2: impl Tr1<As1: 'static> = cdef_et2;
|
||||
pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); }
|
||||
|
||||
const cdef_et3: impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = {
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = core::ops::Range<u8>;
|
||||
fn mk(&self) -> Self::As1 { 0..10 }
|
||||
};
|
||||
let x: impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> = A;
|
||||
x
|
||||
};
|
||||
pub fn use_et3() {
|
||||
let _0 = cdef_et3.mk().clone();
|
||||
let mut s = 0u8;
|
||||
for _1 in _0 {
|
||||
let _2 = _1 + 1u8;
|
||||
s += _2.into();
|
||||
}
|
||||
assert_eq!(s, (0..10).map(|x| x + 1).sum());
|
||||
}
|
||||
|
||||
const cdef_et4: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = {
|
||||
#[derive(Copy, Clone)]
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = A;
|
||||
fn mk(&self) -> A { A }
|
||||
}
|
||||
impl<'a> Tr2<'a> for A {
|
||||
fn tr2(self) -> &'a Self { &A }
|
||||
}
|
||||
let x: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = A;
|
||||
x
|
||||
};
|
||||
|
||||
static sdef_et4: impl Copy + Tr1<As1: for<'a> Tr2<'a>> = cdef_et4;
|
||||
pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); }
|
||||
|
||||
fn main() {
|
||||
let _ = use_et1();
|
||||
let _ = use_et2();
|
||||
let _ = use_et3();
|
||||
let _ = use_et4();
|
||||
}
|
||||
6
src/test/ui/associated-type-bounds/lcsit.stderr
Normal file
6
src/test/ui/associated-type-bounds/lcsit.stderr
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/lcsit.rs:4:12
|
||||
|
|
||||
LL | #![feature(impl_trait_in_bindings)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
64
src/test/ui/associated-type-bounds/rpit.rs
Normal file
64
src/test/ui/associated-type-bounds/rpit.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
trait Tr1 { type As1; fn mk(self) -> Self::As1; }
|
||||
trait Tr2<'a> { fn tr2(self) -> &'a Self; }
|
||||
|
||||
fn assert_copy<T: Copy>(x: T) { let _x = x; let _x = x; }
|
||||
fn assert_static<T: 'static>(_: T) {}
|
||||
fn assert_forall_tr2<T: for<'a> Tr2<'a>>(_: T) {}
|
||||
|
||||
struct S1;
|
||||
#[derive(Copy, Clone)]
|
||||
struct S2;
|
||||
impl Tr1 for S1 { type As1 = S2; fn mk(self) -> Self::As1 { S2 } }
|
||||
|
||||
fn def_et1() -> impl Tr1<As1: Copy> { S1 }
|
||||
pub fn use_et1() { assert_copy(def_et1().mk()); }
|
||||
|
||||
fn def_et2() -> impl Tr1<As1: 'static> { S1 }
|
||||
pub fn use_et2() { assert_static(def_et2().mk()); }
|
||||
|
||||
fn def_et3() -> impl Tr1<As1: Clone + Iterator<Item: Add<u8, Output: Into<u8>>>> {
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = core::ops::Range<u8>;
|
||||
fn mk(self) -> Self::As1 { 0..10 }
|
||||
};
|
||||
A
|
||||
}
|
||||
|
||||
pub fn use_et3() {
|
||||
let _0 = def_et3().mk().clone();
|
||||
let mut s = 0u8;
|
||||
for _1 in _0 {
|
||||
let _2 = _1 + 1u8;
|
||||
s += _2.into();
|
||||
}
|
||||
assert_eq!(s, (0..10).map(|x| x + 1).sum());
|
||||
}
|
||||
|
||||
fn def_et4() -> impl Tr1<As1: for<'a> Tr2<'a>> {
|
||||
#[derive(Copy, Clone)]
|
||||
struct A;
|
||||
impl Tr1 for A {
|
||||
type As1 = A;
|
||||
fn mk(self) -> A { A }
|
||||
}
|
||||
impl<'a> Tr2<'a> for A {
|
||||
fn tr2(self) -> &'a Self { &A }
|
||||
}
|
||||
A
|
||||
}
|
||||
|
||||
pub fn use_et4() { assert_forall_tr2(def_et4().mk()); }
|
||||
|
||||
fn main() {
|
||||
let _ = use_et1();
|
||||
let _ = use_et2();
|
||||
let _ = use_et3();
|
||||
let _ = use_et4();
|
||||
}
|
||||
115
src/test/ui/associated-type-bounds/struct-bounds.rs
Normal file
115
src/test/ui/associated-type-bounds/struct-bounds.rs
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(associated_type_bounds)]
|
||||
|
||||
trait Tr1 { type As1; }
|
||||
trait Tr2 { type As2; }
|
||||
trait Tr3 {}
|
||||
trait Tr4<'a> { type As4; }
|
||||
trait Tr5 { type As5; }
|
||||
|
||||
impl Tr1 for &str { type As1 = bool; }
|
||||
impl Tr2 for bool { type As2 = u8; }
|
||||
impl Tr3 for u8 {}
|
||||
impl Tr1 for () { type As1 = (usize,); }
|
||||
impl<'a> Tr4<'a> for (usize,) { type As4 = u8; }
|
||||
impl Tr5 for bool { type As5 = u16; }
|
||||
|
||||
struct St1<T: Tr1<As1: Tr2>> {
|
||||
outest: T,
|
||||
outer: T::As1,
|
||||
inner: <T::As1 as Tr2>::As2,
|
||||
}
|
||||
|
||||
fn unwrap_1_st1<T: Tr1<As1: Tr2>>(x: St1<T>) -> (T, T::As1, <T::As1 as Tr2>::As2) {
|
||||
(x.outest, x.outer, x.inner)
|
||||
}
|
||||
|
||||
fn unwrap_2_st1<T>(x: St1<T>) -> (T, T::As1, <T::As1 as Tr2>::As2)
|
||||
where
|
||||
T: Tr1,
|
||||
T::As1: Tr2,
|
||||
{
|
||||
unwrap_1_st1(x)
|
||||
}
|
||||
|
||||
struct St2<T: Tr1<As1: Tr2<As2: Tr3>>> {
|
||||
outest: T,
|
||||
outer: T::As1,
|
||||
inner: <T::As1 as Tr2>::As2,
|
||||
}
|
||||
|
||||
struct St3<T: Tr1<As1: 'static>> {
|
||||
outest: T,
|
||||
outer: &'static T::As1,
|
||||
}
|
||||
|
||||
struct St4<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l>>> {
|
||||
f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
|
||||
f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
|
||||
}
|
||||
|
||||
struct St5<'x1, 'x2, T: Tr1<As1: for<'l> Tr4<'l, As4: Copy>>> {
|
||||
f1: &'x1 <T::As1 as Tr4<'x1>>::As4,
|
||||
f2: &'x2 <T::As1 as Tr4<'x2>>::As4,
|
||||
}
|
||||
|
||||
struct St6<T>
|
||||
where
|
||||
T: Tr1<As1: Tr2 + 'static + Tr5>,
|
||||
{
|
||||
f0: T,
|
||||
f1: <T::As1 as Tr2>::As2,
|
||||
f2: &'static T::As1,
|
||||
f3: <T::As1 as Tr5>::As5,
|
||||
}
|
||||
|
||||
struct St7<'a, 'b, T> // `<T::As1 as Tr2>::As2: 'a` is implied.
|
||||
where
|
||||
T: Tr1<As1: Tr2>,
|
||||
{
|
||||
f0: &'a T,
|
||||
f1: &'b <T::As1 as Tr2>::As2,
|
||||
}
|
||||
|
||||
fn _use_st7<'a, 'b, T>(x: St7<'a, 'b, T>)
|
||||
where
|
||||
T: Tr1,
|
||||
T::As1: Tr2,
|
||||
{
|
||||
let _: &'a T = &x.f0;
|
||||
}
|
||||
|
||||
struct StSelf<T> where Self: Tr1<As1: Tr2> {
|
||||
f2: <<Self as Tr1>::As1 as Tr2>::As2,
|
||||
}
|
||||
|
||||
impl Tr1 for StSelf<&'static str> { type As1 = bool; }
|
||||
|
||||
fn main() {
|
||||
let st1 = St1 { outest: "foo", outer: true, inner: 42u8 };
|
||||
assert_eq!(("foo", true, 42), unwrap_1_st1(st1));
|
||||
|
||||
let _ = St2 { outest: "foo", outer: true, inner: 42u8 };
|
||||
|
||||
let _ = St3 { outest: "foo", outer: &true };
|
||||
|
||||
let f1 = (1,);
|
||||
let f2 = (2,);
|
||||
let st4 = St4::<()> { f1: &f1.0, f2: &f2.0, };
|
||||
assert_eq!((&1, &2), (st4.f1, st4.f2));
|
||||
|
||||
// FIXME: requires lazy normalization.
|
||||
/*
|
||||
let f1 = (1,);
|
||||
let f2 = (2,);
|
||||
let st5 = St5::<()> { f1: &f1.0, f2: &f2.0, };
|
||||
assert_eq!((&1, &2), (st5.f1, st5.f2));
|
||||
*/
|
||||
|
||||
let st6 = St6 { f0: "bar", f1: 24u8, f2: &true, f3: 12u16, };
|
||||
assert_eq!(("bar", 24, &true, 12), (st6.f0, st6.f1, st6.f2, st6.f3));
|
||||
|
||||
let stself = StSelf::<&'static str> { f2: 42u8 };
|
||||
assert_eq!(stself.f2, 42u8);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue