fn has(&self, needle: &Path) -> bool {
match self {
PathSet::Set(set) => set.iter().any(|p| p.ends_with(needle)),
- PathSet::Suite(_) => false,
+ PathSet::Suite(suite) => suite.ends_with(needle),
}
}
);
// Ensure we don't build any compiler artifacts.
- assert!(builder.cache.all::<compile::Rustc>().is_empty());
+ assert!(!builder.cache.contains::<compile::Rustc>());
assert_eq!(
first(builder.cache.all::<test::Crate>()),
&[test::Crate {
},]
);
}
+
+ #[test]
+ fn test_exclude() {
+ let mut config = configure(&[], &[]);
+ config.exclude = vec![
+ "src/test/run-pass".into(),
+ "src/tools/tidy".into(),
+ ];
+ config.cmd = Subcommand::Test {
+ paths: Vec::new(),
+ test_args: Vec::new(),
+ rustc_args: Vec::new(),
+ fail_fast: true,
+ doc_tests: DocTests::No,
+ bless: false,
+ compare_mode: None,
+ };
+
+ let build = Build::new(config);
+ let builder = Builder::new(&build);
+ builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
+
+ // Ensure we have really excluded run-pass & tidy
+ assert!(!builder.cache.contains::<test::RunPass>());
+ assert!(!builder.cache.contains::<test::Tidy>());
+
+ // Ensure other tests are not affected.
+ assert!(builder.cache.contains::<test::RunPassFullDeps>());
+ assert!(builder.cache.contains::<test::RustdocUi>());
+ }
}
v.sort_by_key(|&(a, _)| a);
v
}
+
+ #[cfg(test)]
+ pub fn contains<S: Step>(&self) -> bool {
+ self.0.borrow().contains_key(&TypeId::of::<S>())
+ }
}
check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu:
$(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-musl
-TESTS_IN_2 := src/test/run-pass src/test/compile-fail src/test/run-pass-fulldeps
+TESTS_IN_2 := \
+ src/test/ui \
+ src/test/run-pass \
+ src/test/compile-fail \
+ src/test/run-pass-fulldeps \
+ src/tools/linkchecker
appveyor-subset-1:
$(Q)$(BOOTSTRAP) test $(TESTS_IN_2:%=--exclude %)
--- /dev/null
+# `trait_alias`
+
+The tracking issue for this feature is: [#41517]
+
+[#41417]: https://github.com/rust-lang/rust/issues/41517
+
+------------------------
+
+The `trait_alias` feature adds support for trait aliases. These allow aliases
+to be created for one or more traits (currently just a single regular trait plus
+any number of auto-traits), and used wherever traits would normally be used as
+either bounds or trait objects.
+
+```rust
+#![feature(trait_alias)]
+
+trait Foo = std::fmt::Debug + Send;
+trait Bar = Foo + Sync;
+
+// Use trait alias as bound on type parameter.
+fn foo<T: Foo>(v: &T) {
+ println!("{:?}", v);
+}
+
+pub fn main() {
+ foo(&1);
+
+ // Use trait alias for trait objects.
+ let a: &Bar = &123;
+ println!("{:?}", a);
+ let b = Box::new(456) as Box<dyn Foo>;
+ println!("{:?}", b);
+}
+```
let node = match qpath {
hir::QPath::Resolved(None, path) => {
// Turn trait object paths into `TyKind::TraitObject` instead.
- if let Def::Trait(_) = path.def {
- let principal = hir::PolyTraitRef {
- bound_generic_params: hir::HirVec::new(),
- trait_ref: hir::TraitRef {
- path: path.and_then(|path| path),
- ref_id: id.node_id,
- hir_ref_id: id.hir_id,
- },
- span,
- };
+ match path.def {
+ Def::Trait(_) | Def::TraitAlias(_) => {
+ let principal = hir::PolyTraitRef {
+ bound_generic_params: hir::HirVec::new(),
+ trait_ref: hir::TraitRef {
+ path: path.and_then(|path| path),
+ ref_id: id.node_id,
+ hir_ref_id: id.hir_id,
+ },
+ span,
+ };
- // The original ID is taken by the `PolyTraitRef`,
- // so the `Ty` itself needs a different one.
- id = self.next_id();
- hir::TyKind::TraitObject(hir_vec![principal], self.elided_dyn_bound(span))
- } else {
- hir::TyKind::Path(hir::QPath::Resolved(None, path))
+ // The original ID is taken by the `PolyTraitRef`,
+ // so the `Ty` itself needs a different one.
+ id = self.next_id();
+ hir::TyKind::TraitObject(hir_vec![principal], self.elided_dyn_bound(span))
+ }
+ _ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),
}
}
_ => hir::TyKind::Path(qpath),
ItemKind::Struct(..) => Some(Def::Struct(def_id())),
ItemKind::Union(..) => Some(Def::Union(def_id())),
ItemKind::Trait(..) => Some(Def::Trait(def_id())),
- ItemKind::TraitAlias(..) => {
- bug!("trait aliases are not yet implemented (see issue #41517)")
- },
+ ItemKind::TraitAlias(..) => Some(Def::TraitAlias(def_id())),
ItemKind::ExternCrate(_) |
ItemKind::Use(..) |
ItemKind::ForeignMod(..) |
ty::ReEmpty => {
// No variant fields to hash for these ...
}
- ty::ReCanonical(c) => {
- c.hash_stable(hcx, hasher);
- }
ty::ReLateBound(db, ty::BrAnon(i)) => {
db.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher);
}
}
-impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundTyIndex {
+impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundVar {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
Param(param_ty) => {
param_ty.hash_stable(hcx, hasher);
}
+ Bound(bound_ty) => {
+ bound_ty.hash_stable(hcx, hasher);
+ }
Foreign(def_id) => {
def_id.hash_stable(hcx, hasher);
}
FreshTy(a),
FreshIntTy(a),
FreshFloatTy(a),
- BoundTy(a),
});
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
&VtableClosure(ref table_closure) => table_closure.hash_stable(hcx, hasher),
&VtableFnPointer(ref table_fn_pointer) => table_fn_pointer.hash_stable(hcx, hasher),
&VtableGenerator(ref table_generator) => table_generator.hash_stable(hcx, hasher),
+ &VtableTraitAlias(ref table_alias) => table_alias.hash_stable(hcx, hasher),
}
}
}
}
}
+impl<'a, 'gcx, N> HashStable<StableHashingContext<'a>>
+for traits::VtableTraitAliasData<'gcx, N> where N: HashStable<StableHashingContext<'a>> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ let traits::VtableTraitAliasData {
+ alias_def_id,
+ substs,
+ ref nested,
+ } = *self;
+ alias_def_id.hash_stable(hcx, hasher);
+ substs.hash_stable(hcx, hasher);
+ nested.hash_stable(hcx, hasher);
+ }
+}
+
impl_stable_hash_for!(
impl<'tcx, V> for struct infer::canonical::Canonical<'tcx, V> {
max_universe, variables, value
use std::sync::atomic::Ordering;
use ty::fold::{TypeFoldable, TypeFolder};
use ty::subst::Kind;
-use ty::{self, BoundTy, BoundTyIndex, Lift, List, Ty, TyCtxt, TypeFlags};
+use ty::{self, BoundTy, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
query_state: &'cx mut OriginalQueryValues<'tcx>,
// Note that indices is only used once `var_values` is big enough to be
// heap-allocated.
- indices: FxHashMap<Kind<'tcx>, BoundTyIndex>,
+ indices: FxHashMap<Kind<'tcx>, BoundVar>,
canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
needs_canonical_flags: TypeFlags,
+
+ binder_index: ty::DebruijnIndex,
}
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> {
self.tcx
}
+ fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+ where T: TypeFoldable<'tcx>
+ {
+ self.binder_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.binder_index.shift_out(1);
+ t
+ }
+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReLateBound(..) => {
- // leave bound regions alone
- r
+ ty::ReLateBound(index, ..) => {
+ if index >= self.binder_index {
+ bug!("escaping late bound region during canonicalization")
+ } else {
+ r
+ }
}
ty::ReVar(vid) => {
| ty::ReErased => self.canonicalize_region_mode
.canonicalize_free_region(self, r),
- ty::ReClosureBound(..) | ty::ReCanonical(_) => {
- bug!("canonical region encountered during canonicalization")
+ ty::ReClosureBound(..) => {
+ bug!("closure bound region encountered during canonicalization")
}
}
}
bug!("encountered a fresh type during canonicalization")
}
- ty::Infer(ty::BoundTy(_)) => {
- bug!("encountered a canonical type during canonicalization")
+ ty::Bound(bound_ty) => {
+ if bound_ty.index >= self.binder_index {
+ bug!("escaping bound type during canonicalization")
+ } else {
+ t
+ }
}
ty::Closure(..)
where
V: TypeFoldable<'tcx> + Lift<'gcx>,
{
- debug_assert!(
- !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS),
- "canonicalizing a canonical value: {:?}",
- value,
- );
-
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX
} else {
variables: SmallVec::new(),
query_state,
indices: FxHashMap::default(),
+ binder_index: ty::INNERMOST,
};
let out_value = value.fold_with(&mut canonicalizer);
/// or returns an existing variable if `kind` has already been
/// seen. `kind` is expected to be an unbound variable (or
/// potentially a free region).
- fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundTy {
+ fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundVar {
let Canonicalizer {
variables,
query_state,
// direct linear search of `var_values`.
if let Some(idx) = var_values.iter().position(|&k| k == kind) {
// `kind` is already present in `var_values`.
- BoundTyIndex::new(idx)
+ BoundVar::new(idx)
} else {
// `kind` isn't present in `var_values`. Append it. Likewise
// for `info` and `variables`.
*indices = var_values
.iter()
.enumerate()
- .map(|(i, &kind)| (kind, BoundTyIndex::new(i)))
+ .map(|(i, &kind)| (kind, BoundVar::new(i)))
.collect();
}
// The cv is the index of the appended element.
- BoundTyIndex::new(var_values.len() - 1)
+ BoundVar::new(var_values.len() - 1)
}
} else {
// `var_values` is large. Do a hashmap search via `indices`.
variables.push(info);
var_values.push(kind);
assert_eq!(variables.len(), var_values.len());
- BoundTyIndex::new(variables.len() - 1)
+ BoundVar::new(variables.len() - 1)
})
};
- BoundTy {
- level: ty::INNERMOST,
- var,
- }
+ var
}
/// Shorthand helper that creates a canonical region variable for
info: CanonicalVarInfo,
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
- let b = self.canonical_var(info, r.into());
- debug_assert_eq!(ty::INNERMOST, b.level);
- self.tcx().mk_region(ty::ReCanonical(b.var))
+ let var = self.canonical_var(info, r.into());
+ let region = ty::ReLateBound(
+ self.binder_index,
+ ty::BoundRegion::BrAnon(var.as_u32())
+ );
+ self.tcx().mk_region(region)
}
/// Given a type variable `ty_var` of the given kind, first check
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Ty(ty_kind),
};
- let b = self.canonical_var(info, ty_var.into());
- debug_assert_eq!(ty::INNERMOST, b.level);
- self.tcx().mk_infer(ty::InferTy::BoundTy(b))
+ let var = self.canonical_var(info, ty_var.into());
+ self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var)))
}
}
}
//! - a map M (of type `CanonicalVarValues`) from those canonical
//! variables back to the original.
//!
-//! We can then do queries using T2. These will give back constriants
+//! We can then do queries using T2. These will give back constraints
//! on the canonical variables which can be translated, using the map
//! M, into constraints in our source context. This process of
//! translating the results back is done by the
use syntax::source_map::Span;
use ty::fold::TypeFoldable;
use ty::subst::Kind;
-use ty::{self, BoundTyIndex, Lift, List, Region, TyCtxt};
+use ty::{self, BoundVar, Lift, List, Region, TyCtxt};
mod canonicalizer;
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarValues<'tcx> {
- pub var_values: IndexVec<BoundTyIndex, Kind<'tcx>>,
+ pub var_values: IndexVec<BoundVar, Kind<'tcx>>,
}
/// When we canonicalize a value to form a query, we wind up replacing
variables: &List<CanonicalVarInfo>,
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
) -> CanonicalVarValues<'tcx> {
- let var_values: IndexVec<BoundTyIndex, Kind<'tcx>> = variables
+ let var_values: IndexVec<BoundVar, Kind<'tcx>> = variables
.iter()
.map(|info| self.instantiate_canonical_var(span, *info, &universe_map))
.collect();
} where R: Lift<'tcx>
}
-impl<'tcx> Index<BoundTyIndex> for CanonicalVarValues<'tcx> {
+impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
type Output = Kind<'tcx>;
- fn index(&self, value: BoundTyIndex) -> &Kind<'tcx> {
+ fn index(&self, value: BoundVar) -> &Kind<'tcx> {
&self.var_values[value]
}
}
use traits::{Obligation, ObligationCause, PredicateObligation};
use ty::fold::TypeFoldable;
use ty::subst::{Kind, UnpackedKind};
-use ty::{self, BoundTyIndex, Lift, Ty, TyCtxt};
+use ty::{self, BoundVar, Lift, Ty, TyCtxt};
impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
/// The "main method" for a canonicalized trait query. Given the
for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
- &v.var_values[BoundTyIndex::new(index)]
+ &v.var_values[BoundVar::new(index)]
});
match (original_value.unpack(), result_value.unpack()) {
(UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => {
// ...also include the other query region constraints from the query.
output_query_region_constraints.extend(
query_response.value.region_constraints.iter().filter_map(|r_c| {
- let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below
- let k1 = substitute_value(self.tcx, &result_subst, &k1);
- let r2 = substitute_value(self.tcx, &result_subst, &r2);
+ let r_c = substitute_value(self.tcx, &result_subst, r_c);
+
+ // Screen out `'a: 'a` cases -- we skip the binder here but
+ // only care the inner values to one another, so they are still at
+ // consistent binding levels.
+ let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
if k1 != r2.into() {
- Some(ty::Binder::bind(ty::OutlivesPredicate(k1, r2)))
+ Some(r_c)
} else {
None
}
// is directly equal to one of the canonical variables in the
// result, then we can type the corresponding value from the
// input. See the example above.
- let mut opt_values: IndexVec<BoundTyIndex, Option<Kind<'tcx>>> =
+ let mut opt_values: IndexVec<BoundVar, Option<Kind<'tcx>>> =
IndexVec::from_elem_n(None, query_response.variables.len());
// In terms of our example above, we are iterating over pairs like:
match result_value.unpack() {
UnpackedKind::Type(result_value) => {
// e.g., here `result_value` might be `?0` in the example above...
- if let ty::Infer(ty::InferTy::BoundTy(b)) = result_value.sty {
- // in which case we would set `canonical_vars[0]` to `Some(?U)`.
+ if let ty::Bound(b) = result_value.sty {
+ // ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
+
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(b.index, ty::INNERMOST);
opt_values[b.var] = Some(*original_value);
}
}
UnpackedKind::Lifetime(result_value) => {
// e.g., here `result_value` might be `'?1` in the example above...
- if let &ty::RegionKind::ReCanonical(index) = result_value {
- // in which case we would set `canonical_vars[0]` to `Some('static)`.
- opt_values[index] = Some(*original_value);
+ if let &ty::RegionKind::ReLateBound(index, br) = result_value {
+ // ... in which case we would set `canonical_vars[0]` to `Some('static)`.
+
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(index, ty::INNERMOST);
+ opt_values[br.assert_bound_var()] = Some(*original_value);
}
}
}
.enumerate()
.map(|(index, info)| {
if info.is_existential() {
- match opt_values[BoundTyIndex::new(index)] {
+ match opt_values[BoundVar::new(index)] {
Some(k) => k,
None => self.instantiate_canonical_var(cause.span, *info, |u| {
universe_map[u.as_usize()]
// canonical variable; this is taken from
// `query_response.var_values` after applying the substitution
// `result_subst`.
- let substituted_query_response = |index: BoundTyIndex| -> Kind<'tcx> {
+ let substituted_query_response = |index: BoundVar| -> Kind<'tcx> {
query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
};
unsubstituted_region_constraints
.iter()
.map(move |constraint| {
- let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
- let k1 = substitute_value(self.tcx, result_subst, k1);
- let r2 = substitute_value(self.tcx, result_subst, r2);
+ let constraint = substitute_value(self.tcx, result_subst, constraint);
+ let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
Obligation::new(
cause.clone(),
param_env,
match k1.unpack() {
UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives(
- ty::Binder::dummy(
+ ty::Binder::bind(
ty::OutlivesPredicate(r1, r2)
- )),
+ )
+ ),
UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives(
- ty::Binder::dummy(ty::OutlivesPredicate(
- t1, r2
- )))
+ ty::Binder::bind(
+ ty::OutlivesPredicate(t1, r2)
+ )
+ ),
}
)
})
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
variables1: &OriginalQueryValues<'tcx>,
- variables2: impl Fn(BoundTyIndex) -> Kind<'tcx>,
+ variables2: impl Fn(BoundVar) -> Kind<'tcx>,
) -> InferResult<'tcx, ()> {
self.commit_if_ok(|_| {
let mut obligations = vec![];
for (index, value1) in variables1.var_values.iter().enumerate() {
- let value2 = variables2(BoundTyIndex::new(index));
+ let value2 = variables2(BoundVar::new(index));
match (value1.unpack(), value2.unpack()) {
(UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
}
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
})
- .map(ty::Binder::dummy) // no bound regions in the code above
+ .map(ty::Binder::dummy) // no bound vars in the code above
.chain(
outlives_obligations
.map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
- .map(ty::Binder::dummy), // no bound regions in the code above
+ .map(ty::Binder::dummy) // no bound vars in the code above
)
.collect();
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
use infer::canonical::{Canonical, CanonicalVarValues};
-use ty::fold::{TypeFoldable, TypeFolder};
+use ty::fold::TypeFoldable;
use ty::subst::UnpackedKind;
-use ty::{self, Ty, TyCtxt, TypeFlags};
+use ty::{self, TyCtxt};
impl<'tcx, V> Canonical<'tcx, V> {
/// Instantiate the wrapped value, replacing each canonical value
T: TypeFoldable<'tcx>,
{
if var_values.var_values.is_empty() {
- debug_assert!(!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS));
- value.clone()
- } else if !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) {
value.clone()
} else {
- value.fold_with(&mut CanonicalVarValuesSubst { tcx, var_values })
- }
-}
-
-struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
- tcx: TyCtxt<'cx, 'gcx, 'tcx>,
- var_values: &'cx CanonicalVarValues<'tcx>,
-}
-
-impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> {
- fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
- self.tcx
- }
-
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- match t.sty {
- ty::Infer(ty::InferTy::BoundTy(b)) => {
- debug_assert_eq!(ty::INNERMOST, b.level);
- match self.var_values.var_values[b.var].unpack() {
- UnpackedKind::Type(ty) => ty,
- r => bug!("{:?} is a type but value is {:?}", b, r),
- }
+ let fld_r = |br: ty::BoundRegion| {
+ match var_values.var_values[br.assert_bound_var()].unpack() {
+ UnpackedKind::Lifetime(l) => l,
+ r => bug!("{:?} is a region but value is {:?}", br, r),
}
- _ => {
- if !t.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) {
- t
- } else {
- t.super_fold_with(self)
- }
+ };
+
+ let fld_t = |bound_ty: ty::BoundTy| {
+ match var_values.var_values[bound_ty.var].unpack() {
+ UnpackedKind::Type(ty) => ty,
+ r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
}
- }
- }
+ };
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- match r {
- ty::RegionKind::ReCanonical(c) => match self.var_values.var_values[*c].unpack() {
- UnpackedKind::Lifetime(l) => l,
- r => bug!("{:?} is a region but value is {:?}", c, r),
- },
- _ => r.super_fold_with(self),
- }
+ tcx.replace_escaping_bound_vars(value, fld_r, fld_t)
}
}
}
}
- ty::ReCanonical(..) |
ty::ReClosureBound(..) => {
span_bug!(
self.span,
}
// We shouldn't encounter an error message with ReClosureBound.
- ty::ReCanonical(..) | ty::ReClosureBound(..) => {
+ ty::ReClosureBound(..) => {
bug!("encountered unexpected ReClosureBound: {:?}", region,);
}
};
self.tcx().types.re_erased
}
- ty::ReCanonical(..) |
ty::ReClosureBound(..) => {
bug!(
"encountered unexpected region: {:?}",
t
}
- ty::Infer(ty::BoundTy(..)) =>
- bug!("encountered canonical ty during freshening"),
+ ty::Bound(..) =>
+ bug!("encountered bound ty during freshening"),
ty::Generator(..) |
ty::Bool |
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
let tcx = self.tcx();
match (a, b) {
- (&ty::ReCanonical(..), _)
- | (_, &ty::ReCanonical(..))
- | (&ty::ReClosureBound(..), _)
+ (&ty::ReClosureBound(..), _)
| (_, &ty::ReClosureBound(..))
| (&ReLateBound(..), _)
| (_, &ReLateBound(..))
ty, region, origin
);
- assert!(!ty.has_escaping_regions());
+ assert!(!ty.has_escaping_bound_vars());
let components = self.tcx.outlives_components(ty);
self.components_must_outlive(origin, components, region);
predicates
.into_iter()
.filter_map(|p| p.as_ref().to_opt_type_outlives())
- .filter_map(|p| p.no_late_bound_regions())
+ .filter_map(|p| p.no_bound_vars())
.filter(move |p| compare_ty(p.0))
}
}
ty::RePlaceholder(placeholder) => placeholder.universe,
ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid),
ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
- ty::ReCanonical(..) => bug!(
- "region_universe(): encountered canonical region {:?}",
- region
- ),
}
}
// Shouldn't have any LBR here, so we can safely put
// this under a binder below without fear of accidental
// capture.
- assert!(!a.has_escaping_regions());
- assert!(!b.has_escaping_regions());
+ assert!(!a.has_escaping_bound_vars());
+ assert!(!b.has_escaping_bound_vars());
// can't make progress on `A <: B` if both A and B are
// type variables, so record an obligation. We also
map
}
+/// In traits, there is an implicit `Self` type parameter which comes before the generics.
+/// We have to account for this when computing the index of the other generic parameters.
+/// This function returns whether there is such an implicit parameter defined on the given item.
+fn sub_items_have_self_param(node: &hir::ItemKind) -> bool {
+ match *node {
+ hir::ItemKind::Trait(..) |
+ hir::ItemKind::TraitAlias(..) => true,
+ _ => false,
+ }
+}
+
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::All(&self.tcx.hir)
hir::ItemKind::Impl(..) => true,
_ => false,
};
- // These kinds of items have only early bound lifetime parameters.
- let mut index = if let hir::ItemKind::Trait(..) = item.node {
+ // These kinds of items have only early-bound lifetime parameters.
+ let mut index = if sub_items_have_self_param(&item.node) {
1 // Self comes before lifetimes
} else {
0
/// helper method to determine the span to remove when suggesting the
/// deletion of a lifetime
fn lifetime_deletion_span(&self, name: ast::Ident, generics: &hir::Generics) -> Option<Span> {
- if generics.params.len() == 1 {
- // if sole lifetime, remove the `<>` brackets
- Some(generics.span)
- } else {
- generics.params.iter().enumerate().find_map(|(i, param)| {
- if param.name.ident() == name {
- // We also want to delete a leading or trailing comma
- // as appropriate
- if i >= generics.params.len() - 1 {
- Some(generics.params[i - 1].span.shrink_to_hi().to(param.span))
- } else {
- Some(param.span.to(generics.params[i + 1].span.shrink_to_lo()))
+ generics.params.iter().enumerate().find_map(|(i, param)| {
+ if param.name.ident() == name {
+ let mut in_band = false;
+ if let hir::GenericParamKind::Lifetime { kind } = param.kind {
+ if let hir::LifetimeParamKind::InBand = kind {
+ in_band = true;
}
+ }
+ if in_band {
+ Some(param.span)
} else {
- None
+ if generics.params.len() == 1 {
+ // if sole lifetime, remove the entire `<>` brackets
+ Some(generics.span)
+ } else {
+ // if removing within `<>` brackets, we also want to
+ // delete a leading or trailing comma as appropriate
+ if i >= generics.params.len() - 1 {
+ Some(generics.params[i - 1].span.shrink_to_hi().to(param.span))
+ } else {
+ Some(param.span.to(generics.params[i + 1].span.shrink_to_lo()))
+ }
+ }
}
- })
+ } else {
+ None
+ }
+ })
+ }
+
+ // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)`
+ fn suggest_eliding_single_use_lifetime(
+ &self, err: &mut DiagnosticBuilder<'_>, def_id: DefId, lifetime: &hir::Lifetime
+ ) {
+ // FIXME: future work: also suggest `impl Foo<'_>` for `impl<'a> Foo<'a>`
+ let name = lifetime.name.ident();
+ let mut remove_decl = None;
+ if let Some(parent_def_id) = self.tcx.parent(def_id) {
+ if let Some(generics) = self.tcx.hir.get_generics(parent_def_id) {
+ remove_decl = self.lifetime_deletion_span(name, generics);
+ }
+ }
+
+ let mut remove_use = None;
+ let mut find_arg_use_span = |inputs: &hir::HirVec<hir::Ty>| {
+ for input in inputs {
+ if let hir::TyKind::Rptr(lt, _) = input.node {
+ if lt.name.ident() == name {
+ // include the trailing whitespace between the ampersand and the type name
+ let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi());
+ remove_use = Some(
+ self.tcx.sess.source_map()
+ .span_until_non_whitespace(lt_through_ty_span)
+ );
+ break;
+ }
+ }
+ }
+ };
+ if let Node::Lifetime(hir_lifetime) = self.tcx.hir.get(lifetime.id) {
+ if let Some(parent) = self.tcx.hir.find(self.tcx.hir.get_parent(hir_lifetime.id)) {
+ match parent {
+ Node::Item(item) => {
+ if let hir::ItemKind::Fn(decl, _, _, _) = &item.node {
+ find_arg_use_span(&decl.inputs);
+ }
+ },
+ Node::ImplItem(impl_item) => {
+ if let hir::ImplItemKind::Method(sig, _) = &impl_item.node {
+ find_arg_use_span(&sig.decl.inputs);
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+
+ if let (Some(decl_span), Some(use_span)) = (remove_decl, remove_use) {
+ // if both declaration and use deletion spans start at the same
+ // place ("start at" because the latter includes trailing
+ // whitespace), then this is an in-band lifetime
+ if decl_span.shrink_to_lo() == use_span.shrink_to_lo() {
+ err.span_suggestion_with_applicability(
+ use_span,
+ "elide the single-use lifetime",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.multipart_suggestion_with_applicability(
+ "elide the single-use lifetime",
+ vec![(decl_span, String::new()), (use_span, String::new())],
+ Applicability::MachineApplicable,
+ );
+ }
}
}
_ => None,
} {
debug!("id = {:?} span = {:?} name = {:?}", node_id, span, name);
+
+ if name == keywords::UnderscoreLifetime.ident() {
+ continue;
+ }
+
let mut err = self.tcx.struct_span_lint_node(
lint::builtin::SINGLE_USE_LIFETIMES,
id,
span,
&format!("lifetime parameter `{}` only used once", name),
);
- err.span_label(span, "this lifetime...");
- err.span_label(lifetime.span, "...is used only here");
+
+ if span == lifetime.span {
+ // spans are the same for in-band lifetime declarations
+ err.span_label(span, "this lifetime is only used here");
+ } else {
+ err.span_label(span, "this lifetime...");
+ err.span_label(lifetime.span, "...is used only here");
+ }
+ self.suggest_eliding_single_use_lifetime(&mut err, def_id, lifetime);
err.emit();
}
}
if let Some(span) = unused_lt_span {
err.span_suggestion_with_applicability(
span,
- "remove it",
+ "elide the unused lifetime",
String::new(),
Applicability::MachineApplicable,
);
let mut index = 0;
if let Some(parent_id) = parent_id {
let parent = self.tcx.hir.expect_item(parent_id);
- if let hir::ItemKind::Trait(..) = parent.node {
- index += 1; // Self comes first.
+ if sub_items_have_self_param(&parent.node) {
+ index += 1; // Self comes before lifetimes
}
match parent.node {
hir::ItemKind::Trait(_, _, ref generics, ..)
}
&ty::Predicate::TypeOutlives(ref binder) => {
match (
- binder.no_late_bound_regions(),
- binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(),
+ binder.no_bound_vars(),
+ binder.map_bound_ref(|pred| pred.0).no_bound_vars(),
) {
(None, Some(t_a)) => {
select.infcx().register_region_obligation_with_cause(
false
}
- ty::Infer(..) => match in_crate {
+ ty::Bound(..) | ty::Infer(..) => match in_crate {
InCrate::Local => false,
// The inference variable might be unified with a local
// type in that remote crate.
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
- ty::Infer(..) | ty::Error => None,
+ ty::Bound(..) | ty::Infer(..) | ty::Error => None,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
}
}
debug!("normalize_projection_type(projection_ty={:?})",
projection_ty);
- debug_assert!(!projection_ty.has_escaping_regions());
+ debug_assert!(!projection_ty.has_escaping_bound_vars());
// FIXME(#20304) -- cache
}
ty::Predicate::TypeOutlives(ref binder) => {
- // Check if there are higher-ranked regions.
- match binder.no_late_bound_regions() {
+ // Check if there are higher-ranked vars.
+ match binder.no_bound_vars() {
// If there are, inspect the underlying type further.
None => {
// Convert from `Binder<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`.
let binder = binder.map_bound_ref(|pred| pred.0);
- // Check if the type has any bound regions.
- match binder.no_late_bound_regions() {
+ // Check if the type has any bound vars.
+ match binder.no_bound_vars() {
// If so, this obligation is an error (for now). Eventually we should be
// able to support additional cases here, like `for<'a> &'a str: 'a`.
// NOTE: this is duplicate-implemented between here and fulfillment.
domain_goal: PolyDomainGoal<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
) -> GoalKind<'tcx> {
- match domain_goal.no_late_bound_regions() {
+ match domain_goal.no_bound_vars() {
Some(p) => p.into_goal(),
None => GoalKind::Quantified(
QuantifierKind::Universal,
/// Same as above, but for a fn pointer type with the given signature.
VtableFnPointer(VtableFnPointerData<'tcx, N>),
- /// Vtable automatically generated for a generator
+ /// Vtable automatically generated for a generator.
VtableGenerator(VtableGeneratorData<'tcx, N>),
+
+ /// Vtable for a trait alias.
+ VtableTraitAlias(VtableTraitAliasData<'tcx, N>),
}
/// Identifies a particular impl in the source, along with a set of
pub nested: Vec<N>
}
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
+pub struct VtableTraitAliasData<'tcx, N> {
+ pub alias_def_id: DefId,
+ pub substs: &'tcx Substs<'tcx>,
+ pub nested: Vec<N>,
+}
+
/// Creates predicate obligations from the generic bounds.
pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
VtableGenerator(c) => c.nested,
VtableObject(d) => d.nested,
VtableFnPointer(d) => d.nested,
+ VtableTraitAlias(d) => d.nested,
}
}
trait_def_id: d.trait_def_id,
nested: d.nested.into_iter().map(f).collect(),
}),
- VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData {
- fn_ty: p.fn_ty,
- nested: p.nested.into_iter().map(f).collect(),
+ VtableClosure(c) => VtableClosure(VtableClosureData {
+ closure_def_id: c.closure_def_id,
+ substs: c.substs,
+ nested: c.nested.into_iter().map(f).collect(),
}),
VtableGenerator(c) => VtableGenerator(VtableGeneratorData {
generator_def_id: c.generator_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
- VtableClosure(c) => VtableClosure(VtableClosureData {
- closure_def_id: c.closure_def_id,
- substs: c.substs,
- nested: c.nested.into_iter().map(f).collect(),
- })
+ VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData {
+ fn_ty: p.fn_ty,
+ nested: p.nested.into_iter().map(f).collect(),
+ }),
+ VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
+ alias_def_id: d.alias_def_id,
+ substs: d.substs,
+ nested: d.nested.into_iter().map(f).collect(),
+ }),
}
}
}
use super::Selection;
use super::SelectionContext;
use super::SelectionError;
-use super::VtableClosureData;
-use super::VtableGeneratorData;
-use super::VtableFnPointerData;
-use super::VtableImplData;
+use super::{VtableImplData, VtableClosureData, VtableGeneratorData, VtableFnPointerData};
use super::util;
use hir::def_id::DefId;
let ty = ty.super_fold_with(self);
match ty.sty {
- ty::Opaque(def_id, substs) if !substs.has_escaping_regions() => { // (*)
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // (*)
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal {
Reveal::UserFacing => ty,
}
}
- ty::Projection(ref data) if !data.has_escaping_regions() => { // (*)
+ ty::Projection(ref data) if !data.has_escaping_bound_vars() => { // (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
super::VtableClosure(_) |
super::VtableGenerator(_) |
super::VtableFnPointer(_) |
- super::VtableObject(_) => {
+ super::VtableObject(_) |
+ super::VtableTraitAlias(_) => {
debug!("assemble_candidates_from_impls: vtable={:?}",
vtable);
true
confirm_object_candidate(selcx, obligation, obligation_trait_ref),
super::VtableAutoImpl(..) |
super::VtableParam(..) |
- super::VtableBuiltin(..) =>
+ super::VtableBuiltin(..) |
+ super::VtableTraitAlias(..) =>
// we don't create Select candidates with this kind of resolution
span_bug!(
obligation.cause.span,
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
- let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
+ let VtableImplData { impl_def_id, substs, nested } = impl_vtable;
let tcx = selcx.tcx();
let param_env = obligation.param_env;
let infcx = selcx.infcx();
// We don't do cross-snapshot caching of obligations with escaping regions,
// so there's no cache key to use
- predicate.no_late_bound_regions()
+ predicate.no_bound_vars()
.map(|predicate| ProjectionCacheKey {
// We don't attempt to match up with a specific type-variable state
// from a specific call to `opt_normalize_projection_type` - if
| ty::Param(_)
| ty::Opaque(..)
| ty::Infer(_)
+ | ty::Bound(..)
| ty::Generator(..) => false,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let ty = ty.super_fold_with(self);
match ty.sty {
- ty::Opaque(def_id, substs) if !substs.has_escaping_regions() => {
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// (*)
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal {
}
}
- ty::Projection(ref data) if !data.has_escaping_regions() => {
+ ty::Projection(ref data) if !data.has_escaping_bound_vars() => {
// (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) |
ty::Predicate::ConstEvaluatable(..) => None,
- ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map(
+ ty::Predicate::RegionOutlives(ref data) => data.no_bound_vars().map(
|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a),
),
})
use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
use super::{
VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl,
- VtableObject, VtableParam,
+ VtableObject, VtableParam, VtableTraitAlias,
};
use super::{
VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData,
- VtableGeneratorData, VtableImplData, VtableObjectData,
+ VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData,
};
use dep_graph::{DepKind, DepNodeIndex};
/// types generated for a fn pointer type (e.g., `fn(int)->int`)
FnPointerCandidate,
+ TraitAliasCandidate(DefId),
+
ObjectCandidate,
BuiltinObjectCandidate,
ImplCandidate(def_id) => ImplCandidate(def_id),
AutoImplCandidate(def_id) => AutoImplCandidate(def_id),
ProjectionCandidate => ProjectionCandidate,
+ ClosureCandidate => ClosureCandidate,
+ GeneratorCandidate => GeneratorCandidate,
FnPointerCandidate => FnPointerCandidate,
+ TraitAliasCandidate(def_id) => TraitAliasCandidate(def_id),
ObjectCandidate => ObjectCandidate,
BuiltinObjectCandidate => BuiltinObjectCandidate,
BuiltinUnsizeCandidate => BuiltinUnsizeCandidate,
- ClosureCandidate => ClosureCandidate,
- GeneratorCandidate => GeneratorCandidate,
ParamCandidate(ref trait_ref) => {
return tcx.lift(trait_ref).map(ParamCandidate);
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, Selection<'tcx>> {
debug!("select({:?})", obligation);
- debug_assert!(!obligation.predicate.has_escaping_regions());
+ debug_assert!(!obligation.predicate.has_escaping_bound_vars());
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
match obligation.predicate {
ty::Predicate::Trait(ref t) => {
- debug_assert!(!t.has_escaping_regions());
+ debug_assert!(!t.has_escaping_bound_vars());
let obligation = obligation.with(t.clone());
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
}
},
ty::Predicate::TypeOutlives(ref binder) => {
- assert!(!binder.has_escaping_regions());
- // Check if the type has higher-ranked regions.
- if binder.skip_binder().0.has_escaping_regions() {
+ assert!(!binder.has_escaping_bound_vars());
+ // Check if the type has higher-ranked vars.
+ if binder.skip_binder().0.has_escaping_bound_vars() {
// If so, this obligation is an error (for now). Eventually we should be
// able to support additional cases here, like `for<'a> &'a str: 'a`.
Ok(EvaluatedToErr)
}
} else {
- // If the type has no late bound regions, then if we assign all
+ // If the type has no late bound vars, then if we assign all
// the inference variables in it to be 'static, then the type
// will be 'static itself.
//
"candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
cache_fresh_trait_pred, stack
);
- debug_assert!(!stack.obligation.predicate.has_escaping_regions());
+ debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
if let Some(c) =
self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred)
let predicate = self.infcx()
.resolve_type_vars_if_possible(&obligation.predicate);
- // ok to skip binder because of the nature of the
+ // OK to skip binder because of the nature of the
// trait-ref-is-knowable check, which does not care about
// bound regions
let trait_ref = predicate.skip_binder().trait_ref;
ambiguous: false,
};
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?;
+
// Other bounds. Consider both in-scope bounds from fn decl
// and applicable impls. There is a certain set of precedence rules here.
let def_id = obligation.predicate.def_id();
placeholder_map: &infer::PlaceholderMap<'tcx>,
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
) -> bool {
- debug_assert!(!skol_trait_ref.has_escaping_regions());
+ debug_assert!(!skol_trait_ref.has_escaping_bound_vars());
if self.infcx
.at(&obligation.cause, obligation.param_env)
.sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
return Ok(());
}
- // ok to skip binder because the substs on generator types never
+ // OK to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
// type/region parameters
let self_ty = *obligation.self_ty().skip_binder();
}
};
- // ok to skip binder because the substs on closure types never
+ // OK 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 {
return Ok(());
}
- // ok to skip binder because what we are inspecting doesn't involve bound regions
+ // OK 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(_)) => {
// T: Trait
// so it seems ok if we (conservatively) fail to accept that `Unsize`
// obligation above. Should be possible to extend this in the future.
- let source = match obligation.self_ty().no_late_bound_regions() {
+ let source = match obligation.self_ty().no_bound_vars() {
Some(t) => t,
None => {
// Don't add any candidates if there are bound regions.
}
}
+ fn assemble_candidates_for_trait_alias(
+ &mut self,
+ 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
+ let self_ty = *obligation.self_ty().skip_binder();
+ debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
+
+ let def_id = obligation.predicate.def_id();
+
+ if ty::is_trait_alias(self.tcx(), def_id) {
+ candidates.vec.push(TraitAliasCandidate(def_id.clone()));
+ }
+
+ Ok(())
+ }
+
///////////////////////////////////////////////////////////////////////////
// WINNOW
//
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
- | BuiltinCandidate { .. } => {
+ | BuiltinCandidate { .. }
+ | TraitAliasCandidate(..) => {
// Global bounds from the where clause should be ignored
// here (see issue #50825). Otherwise, we have a where
// clause so don't go around looking for impls.
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
- | BuiltinCandidate { .. } => true,
+ | BuiltinCandidate { .. }
+ | TraitAliasCandidate(..) => true,
ObjectCandidate | ProjectionCandidate => {
// Arbitrarily give param candidates priority
// over projection and object candidates.
ty::Infer(ty::TyVar(_)) => Ambiguous,
ty::UnnormalizedProjection(..)
- | ty::Infer(ty::BoundTy(_))
+ | ty::Bound(_)
| ty::Infer(ty::FreshTy(_))
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_)) => {
}
ty::UnnormalizedProjection(..)
- | ty::Infer(ty::BoundTy(_))
+ | ty::Bound(_)
| ty::Infer(ty::FreshTy(_))
| ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_)) => {
| ty::Param(..)
| ty::Foreign(..)
| ty::Projection(..)
- | ty::Infer(ty::BoundTy(_))
+ | ty::Bound(_)
| ty::Infer(ty::TyVar(_))
| ty::Infer(ty::FreshTy(_))
| ty::Infer(ty::FreshIntTy(_))
Ok(VtableParam(obligations))
}
+ ImplCandidate(impl_def_id) => Ok(VtableImpl(self.confirm_impl_candidate(
+ obligation,
+ impl_def_id,
+ ))),
+
AutoImplCandidate(trait_def_id) => {
let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
Ok(VtableAutoImpl(data))
}
- ImplCandidate(impl_def_id) => Ok(VtableImpl(self.confirm_impl_candidate(
- obligation,
- impl_def_id,
- ))),
+ ProjectionCandidate => {
+ self.confirm_projection_candidate(obligation);
+ Ok(VtableParam(Vec::new()))
+ }
ClosureCandidate => {
let vtable_closure = self.confirm_closure_candidate(obligation)?;
Ok(VtableGenerator(vtable_generator))
}
- BuiltinObjectCandidate => {
- // This indicates something like `(Trait+Send) :
- // Send`. In this case, we know that this holds
- // because that's what the object type is telling us,
- // and there's really no additional obligations to
- // prove and no types in particular to unify etc.
- Ok(VtableParam(Vec::new()))
+ FnPointerCandidate => {
+ let data = self.confirm_fn_pointer_candidate(obligation)?;
+ Ok(VtableFnPointer(data))
+ }
+
+ TraitAliasCandidate(alias_def_id) => {
+ let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
+ Ok(VtableTraitAlias(data))
}
ObjectCandidate => {
Ok(VtableObject(data))
}
- FnPointerCandidate => {
- let data = self.confirm_fn_pointer_candidate(obligation)?;
- Ok(VtableFnPointer(data))
- }
-
- ProjectionCandidate => {
- self.confirm_projection_candidate(obligation);
+ BuiltinObjectCandidate => {
+ // This indicates something like `(Trait+Send) :
+ // Send`. In this case, we know that this holds
+ // because that's what the object type is telling us,
+ // and there's really no additional obligations to
+ // prove and no types in particular to unify etc.
Ok(VtableParam(Vec::new()))
}
self.vtable_auto_impl(obligation, trait_def_id, types)
}
- /// See `confirm_auto_impl_candidate`
+ /// See `confirm_auto_impl_candidate`.
fn vtable_auto_impl(
&mut self,
obligation: &TraitObligation<'tcx>,
// this time not in a probe.
self.in_snapshot(|this, snapshot| {
let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot);
- debug!("confirm_impl_candidate substs={:?}", substs);
+ debug!("confirm_impl_candidate: substs={:?}", substs);
let cause = obligation.derived_cause(ImplDerivedObligation);
this.vtable_impl(
impl_def_id,
) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> {
debug!("confirm_object_candidate({:?})", obligation);
- // FIXME skipping binder here seems wrong -- we should
- // probably flatten the binder from the obligation and the
- // binder from the object. Have to try to make a broken test
- // case that results. -nmatsakis
+ // FIXME(nmatsakis) skipping binder here seems wrong -- we should
+ // probably flatten the binder from the obligation and the binder
+ // from the object. Have to try to make a broken test case that
+ // results.
let self_ty = self.infcx
.shallow_resolve(*obligation.self_ty().skip_binder());
let poly_trait_ref = match self_ty.sty {
) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!("confirm_fn_pointer_candidate({:?})", obligation);
- // ok to skip binder; it is reintroduced below
+ // OK 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());
})
}
+ fn confirm_trait_alias_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ alias_def_id: DefId,
+ ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> {
+ debug!(
+ "confirm_trait_alias_candidate({:?}, {:?})",
+ obligation, alias_def_id
+ );
+
+ self.in_snapshot(|this, snapshot| {
+ let (predicate, placeholder_map) = this.infcx()
+ .replace_late_bound_regions_with_placeholders(&obligation.predicate);
+ let trait_ref = predicate.trait_ref;
+ let trait_def_id = trait_ref.def_id;
+ let substs = trait_ref.substs;
+
+ let trait_obligations = this.impl_or_trait_obligations(
+ obligation.cause.clone(),
+ obligation.recursion_depth,
+ obligation.param_env,
+ trait_def_id,
+ &substs,
+ placeholder_map,
+ snapshot,
+ );
+
+ debug!(
+ "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}",
+ trait_def_id, trait_obligations
+ );
+
+ VtableTraitAliasData {
+ alias_def_id,
+ substs: substs,
+ nested: trait_obligations,
+ }
+ })
+ }
+
fn confirm_generator_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
- // ok to skip binder because the substs on generator types never
+ // OK to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
// type/region parameters
let self_ty = self.infcx
.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
+ // OK to skip binder because the substs on closure types never
// touch bound regions, they just capture the in-scope
// type/region parameters
let self_ty = self.infcx
// assemble_candidates_for_unsizing should ensure there are no late bound
// regions here. See the comment there for more details.
let source = self.infcx
- .shallow_resolve(obligation.self_ty().no_late_bound_regions().unwrap());
+ .shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
let target = obligation
.predicate
.skip_binder()
super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
super::VtableBuiltin(ref d) => write!(f, "{:?}", d),
+
+ super::VtableTraitAlias(ref d) => write!(f, "{:?}", d),
}
}
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
- "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})",
+ "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})",
self.impl_def_id, self.substs, self.nested
)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
- "VtableGenerator(generator_def_id={:?}, substs={:?}, nested={:?})",
+ "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
self.generator_def_id, self.substs, self.nested
)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
- "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})",
+ "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
self.closure_def_id, self.substs, self.nested
)
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "VtableBuiltin(nested={:?})", self.nested)
+ write!(f, "VtableBuiltinData(nested={:?})", self.nested)
}
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
- "VtableObject(upcast={:?}, vtable_base={}, nested={:?})",
+ "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})",
self.upcast_trait_ref, self.vtable_base, self.nested
)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
- "VtableFnPointer(fn_ty={:?}, nested={:?})",
+ "VtableFnPointerData(fn_ty={:?}, nested={:?})",
self.fn_ty, self.nested
)
}
}
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})",
+ self.alias_def_id, self.substs, self.nested
+ )
+ }
+}
+
impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
nested,
})
),
+ traits::VtableTraitAlias(traits::VtableTraitAliasData {
+ alias_def_id,
+ substs,
+ nested,
+ }) => tcx.lift(&substs).map(|substs|
+ traits::VtableTraitAlias(traits::VtableTraitAliasData {
+ alias_def_id,
+ substs,
+ nested,
+ })
+ ),
}
}
}
} where N: TypeFoldable<'tcx>
}
+BraceStructTypeFoldableImpl! {
+ impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableTraitAliasData<'tcx, N> {
+ alias_def_id, substs, nested
+ } where N: TypeFoldable<'tcx>
+}
+
EnumTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
(traits::VtableImpl)(a),
(traits::VtableParam)(a),
(traits::VtableBuiltin)(a),
(traits::VtableObject)(a),
+ (traits::VtableTraitAlias)(a),
} where N: TypeFoldable<'tcx>
}
}
}
-impl<'tcx,I:Iterator<Item=ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
+impl<'tcx,I:Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
type Item = ty::PolyTraitRef<'tcx>;
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
sty_debug_print!(
self,
Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr,
- Generator, GeneratorWitness, Dynamic, Closure, Tuple,
+ Generator, GeneratorWitness, Dynamic, Closure, Tuple, Bound,
Param, Infer, UnnormalizedProjection, Projection, Opaque, Foreign);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
ty::Infer(ty::TyVar(_)) => "inferred type".into(),
ty::Infer(ty::IntVar(_)) => "integral variable".into(),
ty::Infer(ty::FloatVar(_)) => "floating-point variable".into(),
- ty::Infer(ty::BoundTy(_)) |
+ ty::Bound(_) |
ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
ty::Foreign(def_id) => {
Some(ForeignSimplifiedType(def_id))
}
- ty::Infer(_) | ty::Error => None,
+ ty::Bound(..) | ty::Infer(_) | ty::Error => None,
}
}
self.add_substs(&substs.substs);
}
+ &ty::Bound(bound_ty) => {
+ self.add_binder(bound_ty.index);
+ }
+
&ty::Infer(infer) => {
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
self.add_flags(TypeFlags::HAS_TY_INFER);
match infer {
ty::FreshTy(_) |
ty::FreshIntTy(_) |
- ty::FreshFloatTy(_) |
- ty::BoundTy(_) => {
- self.add_flags(TypeFlags::HAS_CANONICAL_VARS);
+ ty::FreshFloatTy(_) => {
}
ty::TyVar(_) |
&ty::Projection(ref data) => {
// currently we can't normalize projections that
// include bound regions, so track those separately.
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION);
}
self.add_flags(TypeFlags::HAS_PROJECTION);
/// bound by `binder` or bound by some binder outside of `binder`.
/// If `binder` is `ty::INNERMOST`, this indicates whether
/// there are any late-bound regions that appear free.
- fn has_regions_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
- self.visit_with(&mut HasEscapingRegionsVisitor { outer_index: binder })
+ fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+ self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder })
}
/// True if this `self` has any regions that escape `binder` (and
/// hence are not bound by it).
- fn has_regions_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
- self.has_regions_bound_at_or_above(binder.shifted_in(1))
+ fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
+ self.has_vars_bound_at_or_above(binder.shifted_in(1))
}
- fn has_escaping_regions(&self) -> bool {
- self.has_regions_bound_at_or_above(ty::INNERMOST)
+ fn has_escaping_bound_vars(&self) -> bool {
+ self.has_vars_bound_at_or_above(ty::INNERMOST)
}
fn has_type_flags(&self, flags: TypeFlags) -> bool {
}
///////////////////////////////////////////////////////////////////////////
-// Late-bound region replacer
+// Bound vars replacer
-// Replaces the escaping regions in a type.
-
-struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+/// Replaces the escaping bound vars (late bound regions or bound types) in a type.
+struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
/// As with `RegionFolder`, represents the index of a binder *just outside*
current_index: ty::DebruijnIndex,
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
- map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>
+ fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> ty::Ty<'tcx> + 'a),
+}
+
+impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> {
+ fn new<F, G>(
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ fld_r: &'a mut F,
+ fld_t: &'a mut G
+ ) -> Self
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>
+ {
+ BoundVarReplacer {
+ tcx,
+ current_index: ty::INNERMOST,
+ fld_r,
+ fld_t,
+ }
+ }
+}
+
+impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
+ self.current_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.current_index.shift_out(1);
+ t
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ match t.sty {
+ ty::Bound(bound_ty) => {
+ if bound_ty.index == self.current_index {
+ let fld_t = &mut self.fld_t;
+ let ty = fld_t(bound_ty);
+ ty::fold::shift_vars(
+ self.tcx,
+ &ty,
+ self.current_index.as_u32()
+ )
+ } else {
+ t
+ }
+ }
+ _ => {
+ if !t.has_vars_bound_at_or_above(self.current_index) {
+ // Nothing more to substitute.
+ t
+ } else {
+ t.super_fold_with(self)
+ }
+ }
+ }
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match *r {
+ ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
+ let fld_r = &mut self.fld_r;
+ let region = fld_r(br);
+ if let ty::ReLateBound(debruijn1, br) = *region {
+ // If the callback returns a late-bound region,
+ // that region should always use the INNERMOST
+ // debruijn index. Then we adjust it to the
+ // correct depth.
+ assert_eq!(debruijn1, ty::INNERMOST);
+ self.tcx.mk_region(ty::ReLateBound(debruijn, br))
+ } else {
+ region
+ }
+ }
+ _ => r
+ }
+ }
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// same `BoundRegion` will reuse the previous result. A map is
/// returned at the end with each bound region and the free region
/// that replaced it.
- pub fn replace_late_bound_regions<T,F>(self,
+ ///
+ /// This method only replaces late bound regions and the result may still
+ /// contain escaping bound types.
+ pub fn replace_late_bound_regions<T, F>(
+ self,
value: &Binder<T>,
- mut f: F)
- -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
- where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
- T : TypeFoldable<'tcx>,
+ mut fld_r: F
+ ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ T: TypeFoldable<'tcx>
{
- let mut replacer = RegionReplacer::new(self, &mut f);
+ let mut map = BTreeMap::new();
+ let mut real_fldr = |br| {
+ *map.entry(br).or_insert_with(|| fld_r(br))
+ };
+
+ // identity for bound types
+ let mut fld_t = |bound_ty| self.mk_ty(ty::Bound(bound_ty));
+
+ let mut replacer = BoundVarReplacer::new(self, &mut real_fldr, &mut fld_t);
let result = value.skip_binder().fold_with(&mut replacer);
- (result, replacer.map)
+ (result, map)
+ }
+
+ /// Replace all escaping bound vars. The `fld_r` closure replaces escaping
+ /// bound regions while the `fld_t` closure replaces escaping bound types.
+ pub fn replace_escaping_bound_vars<T, F, G>(
+ self,
+ value: &T,
+ mut fld_r: F,
+ mut fld_t: G
+ ) -> T
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
+ T: TypeFoldable<'tcx>
+ {
+ if !value.has_escaping_bound_vars() {
+ value.clone()
+ } else {
+ let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t);
+ let result = value.fold_with(&mut replacer);
+ result
+ }
+ }
+
+ /// Replace all types or regions bound by the given `Binder`. The `fld_r`
+ /// closure replaces bound regions while the `fld_t` closure replaces bound
+ /// types.
+ pub fn replace_bound_vars<T, F, G>(
+ self,
+ value: &Binder<T>,
+ fld_r: F,
+ fld_t: G
+ ) -> T
+ where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+ G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>,
+ T: TypeFoldable<'tcx>
+ {
+ self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t)
}
/// Replace any late-bound regions bound in `value` with
}
}
-impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
- fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
- -> RegionReplacer<'a, 'gcx, 'tcx>
- where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>
- {
- RegionReplacer {
+///////////////////////////////////////////////////////////////////////////
+// Shifter
+//
+// Shifts the De Bruijn indices on all escaping bound vars by a
+// fixed amount. Useful in substitution or when otherwise introducing
+// a binding level that is not intended to capture the existing bound
+// vars. See comment on `shift_vars_through_binders` method in
+// `subst.rs` for more details.
+
+struct Shifter<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+
+ current_index: ty::DebruijnIndex,
+ amount: u32,
+}
+
+impl Shifter<'a, 'gcx, 'tcx> {
+ pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32) -> Self {
+ Shifter {
tcx,
current_index: ty::INNERMOST,
- fld_r,
- map: BTreeMap::default()
+ amount,
}
}
}
-impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
t
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.has_regions_bound_at_or_above(self.current_index) {
- return t;
- }
-
- t.super_fold_with(self)
- }
-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
- let fld_r = &mut self.fld_r;
- let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
- if let ty::ReLateBound(debruijn1, br) = *region {
- // If the callback returns a late-bound region,
- // that region should always use the INNERMOST
- // debruijn index. Then we adjust it to the
- // correct depth.
- assert_eq!(debruijn1, ty::INNERMOST);
- self.tcx.mk_region(ty::ReLateBound(debruijn, br))
+ ty::ReLateBound(debruijn, br) => {
+ if self.amount == 0 || debruijn < self.current_index {
+ r
} else {
- region
+ let shifted = ty::ReLateBound(debruijn.shifted_in(self.amount), br);
+ self.tcx.mk_region(shifted)
}
}
_ => r
}
}
-}
-///////////////////////////////////////////////////////////////////////////
-// Region shifter
-//
-// Shifts the De Bruijn indices on all escaping bound regions by a
-// fixed amount. Useful in substitution or when otherwise introducing
-// a binding level that is not intended to capture the existing bound
-// regions. See comment on `shift_regions_through_binders` method in
-// `subst.rs` for more details.
+ fn fold_ty(&mut self, ty: ty::Ty<'tcx>) -> ty::Ty<'tcx> {
+ match ty.sty {
+ ty::Bound(bound_ty) => {
+ if self.amount == 0 || bound_ty.index < self.current_index {
+ ty
+ } else {
+ let shifted = ty::BoundTy {
+ index: bound_ty.index.shifted_in(self.amount),
+ var: bound_ty.var,
+ kind: bound_ty.kind,
+ };
+ self.tcx.mk_ty(ty::Bound(shifted))
+ }
+ }
-pub fn shift_region(region: ty::RegionKind, amount: u32) -> ty::RegionKind {
- match region {
- ty::ReLateBound(debruijn, br) => {
- ty::ReLateBound(debruijn.shifted_in(amount), br)
- }
- _ => {
- region
+ _ => ty.super_fold_with(self),
}
}
}
-pub fn shift_region_ref<'a, 'gcx, 'tcx>(
+pub fn shift_region<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
region: ty::Region<'tcx>,
- amount: u32)
- -> ty::Region<'tcx>
-{
+ amount: u32
+) -> ty::Region<'tcx> {
match region {
- &ty::ReLateBound(debruijn, br) if amount > 0 => {
- tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br))
+ ty::ReLateBound(debruijn, br) if amount > 0 => {
+ tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br))
}
_ => {
region
}
}
-pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- amount: u32,
- value: &T) -> T
- where T: TypeFoldable<'tcx>
-{
- debug!("shift_regions(value={:?}, amount={})",
+pub fn shift_vars<'a, 'gcx, 'tcx, T>(
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ value: &T,
+ amount: u32
+) -> T where T: TypeFoldable<'tcx> {
+ debug!("shift_vars(value={:?}, amount={})",
value, amount);
- value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
- shift_region_ref(tcx, region, amount)
- }))
+ value.fold_with(&mut Shifter::new(tcx, amount))
}
-/// An "escaping region" is a bound region whose binder is not part of `t`.
+/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
+/// bound region or a bound type.
///
/// So, for example, consider a type like the following, which has two binders:
///
/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
/// fn type*, that type has an escaping region: `'a`.
///
-/// Note that what I'm calling an "escaping region" is often just called a "free region". However,
-/// we already use the term "free region". It refers to the regions that we use to represent bound
-/// regions on a fn definition while we are typechecking its body.
+/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
+/// we already use the term "free var". It refers to the regions or types that we use to represent
+/// bound regions or type params on a fn definition while we are typechecking its body.
///
/// To clarify, conceptually there is no particular difference between
-/// an "escaping" region and a "free" region. However, there is a big
+/// an "escaping" var and a "free" var. However, there is a big
/// difference in practice. Basically, when "entering" a binding
/// level, one is generally required to do some sort of processing to
-/// a bound region, such as replacing it with a fresh/placeholder
-/// region, or making an entry in the environment to represent the
-/// scope to which it is attached, etc. An escaping region represents
-/// a bound region for which this processing has not yet been done.
-struct HasEscapingRegionsVisitor {
+/// a bound var, such as replacing it with a fresh/placeholder
+/// var, or making an entry in the environment to represent the
+/// scope to which it is attached, etc. An escaping var represents
+/// a bound var for which this processing has not yet been done.
+struct HasEscapingVarsVisitor {
/// Anything bound by `outer_index` or "above" is escaping
outer_index: ty::DebruijnIndex,
}
-impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor {
+impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
self.outer_index.shift_in(1);
let result = t.super_visit_with(self);
// `outer_index`, that means that `t` contains some content
// bound at `outer_index` or above (because
// `outer_exclusive_binder` is always 1 higher than the
- // content in `t`). Therefore, `t` has some escaping regions.
+ // content in `t`). Therefore, `t` has some escaping vars.
t.outer_exclusive_binder > self.outer_index
}
impl<'a, 'b, 'tcx> Instance<'tcx> {
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Instance<'tcx> {
- assert!(!substs.has_escaping_regions(),
+ assert!(!substs.has_escaping_bound_vars(),
"substs of instance {:?} not normalized for codegen: {:?}",
def_id, substs);
Instance { def: InstanceDef::Item(def_id), substs: substs }
None
}
}
- traits::VtableAutoImpl(..) | traits::VtableParam(..) => None
+ traits::VtableAutoImpl(..) |
+ traits::VtableParam(..) |
+ traits::VtableTraitAlias(..) => None
}
}
ty::Param(_) |
ty::Opaque(..) |
ty::Infer(_) |
+ ty::Bound(..) |
ty::Error |
ty::GeneratorWitness(..) |
ty::Never |
}
tcx.layout_raw(param_env.and(normalized))?
}
- ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
+
+ ty::Bound(..) |
+ ty::UnnormalizedProjection(..) |
+ ty::GeneratorWitness(..) |
+ ty::Infer(_) => {
bug!("LayoutDetails::compute: unexpected type `{}`", ty)
}
+
ty::Param(_) | ty::Error => {
return Err(LayoutError::Unknown(ty));
}
}
}
- ty::Projection(_) | ty::UnnormalizedProjection(..) |
+ ty::Projection(_) | ty::UnnormalizedProjection(..) | ty::Bound(..) |
ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | ty::Error => {
bug!("TyLayout::field_type: unexpected type `{}`", this.ty)
}
use hir;
-pub use self::sty::{Binder, BoundTy, BoundTyIndex, DebruijnIndex, INNERMOST};
+pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST};
pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig};
pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
// Currently we can't normalize projections w/ bound regions.
const HAS_NORMALIZABLE_PROJECTION = 1 << 12;
- // Set if this includes a "canonical" type or region var --
- // ought to be true only for the results of canonicalization.
- const HAS_CANONICAL_VARS = 1 << 13;
-
/// Does this have any `ReLateBound` regions? Used to check
/// if a global bound is safe to evaluate.
- const HAS_RE_LATE_BOUND = 1 << 14;
+ const HAS_RE_LATE_BOUND = 1 << 13;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_TY_CLOSURE.bits |
TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
- TypeFlags::HAS_CANONICAL_VARS.bits |
TypeFlags::HAS_RE_LATE_BOUND.bits;
}
}
/// would be the type parameters.
Trait(PolyTraitPredicate<'tcx>),
- /// where 'a : 'b
+ /// where `'a : 'b`
RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
- /// where T : 'a
+ /// where `T : 'a`
TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
- /// where <T as TraitRef>::Name == X, approximately.
- /// See `ProjectionPredicate` struct for details.
+ /// where `<T as TraitRef>::Name == X`, approximately.
+ /// See the `ProjectionPredicate` struct for details.
Projection(PolyProjectionPredicate<'tcx>),
- /// no syntax: T WF
+ /// no syntax: `T` well-formed
WellFormed(Ty<'tcx>),
/// trait must be object-safe
ObjectSafe(DefId),
/// No direct syntax. May be thought of as `where T : FnFoo<...>`
- /// for some substitutions `...` and T being a closure type.
+ /// for some substitutions `...` and `T` being a closure type.
/// Satisfied (or refuted) once we know the closure's kind.
ClosureKind(DefId, ClosureSubsts<'tcx>, ClosureKind),
}
}
+ Bound(..) |
Infer(..) => {
bug!("unexpected type `{:?}` in sized_constraint_for_ty",
ty)
}
}
- /// Determine whether an item is annotated with an attribute
+ /// Determine whether an item is annotated with an attribute.
pub fn has_attr(self, did: DefId, attr: &str) -> bool {
attr::contains_name(&self.get_attrs(did), attr)
}
self.optimized_mir(def_id).generator_layout.as_ref().unwrap()
}
- /// Given the def_id of an impl, return the def_id of the trait it implements.
+ /// Given the def-id of an impl, return the def_id of the trait it implements.
/// If it implements no trait, return `None`.
pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
self.impl_trait_ref(def_id).map(|tr| tr.def_id)
}
- /// If the given def ID describes a method belonging to an impl, return the
- /// ID of the impl that the method belongs to. Otherwise, return `None`.
+ /// If the given defid describes a method belonging to an impl, return the
+ /// def-id of the impl that the method belongs to. Otherwise, return `None`.
pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
let item = if def_id.krate != LOCAL_CRATE {
if let Some(Def::Method(_)) = self.describe_def(def_id) {
})
}
-/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition
+/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition.
pub fn is_impl_trait_defn(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<DefId> {
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
if let Node::Item(item) = tcx.hir.get(node_id) {
None
}
-/// See `ParamEnv` struct def'n for details.
+/// Returns `true` if `def_id` is a trait alias.
+pub fn is_trait_alias(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> bool {
+ if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
+ if let Node::Item(item) = tcx.hir.get(node_id) {
+ if let hir::ItemKind::TraitAlias(..) = item.node {
+ return true;
+ }
+ }
+ }
+ false
+}
+
+/// See `ParamEnv` struct definition for details.
fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ParamEnv<'tcx>
// we simply fallback to the most restrictive rule, which
// requires that `Pi: 'a` for all `i`.
ty::Projection(ref data) => {
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
// best case: no escaping regions, so push the
// projection and skip the subtree (thus generating no
// constraints for Pi). This defers the choice between
ty::FnDef(..) | // OutlivesFunction (*)
ty::FnPtr(_) | // OutlivesFunction (*)
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
+ ty::Bound(..) |
ty::Error => {
// (*) Bare functions and traits are both binders. In the
// RFC, this means we would add the bound regions to the
ty::UnnormalizedProjection(data.fold_with(folder))
}
ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
- ty::Bool | ty::Char | ty::Str | ty::Int(_) |
- ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
- ty::Param(..) | ty::Never | ty::Foreign(..) => return self
+
+ ty::Bool |
+ ty::Char |
+ ty::Str |
+ ty::Int(_) |
+ ty::Uint(_) |
+ ty::Float(_) |
+ ty::Error |
+ ty::Infer(_) |
+ ty::Param(..) |
+ ty::Bound(..) |
+ ty::Never |
+ ty::Foreign(..) => return self
};
if self.sty == sty {
data.visit_with(visitor)
}
ty::Opaque(_, ref substs) => substs.visit_with(visitor),
- ty::Bool | ty::Char | ty::Str | ty::Int(_) |
- ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
- ty::Param(..) | ty::Never | ty::Foreign(..) => false,
+
+ ty::Bool |
+ ty::Char |
+ ty::Str |
+ ty::Int(_) |
+ ty::Uint(_) |
+ ty::Float(_) |
+ ty::Error |
+ ty::Infer(_) |
+ ty::Bound(..) |
+ ty::Param(..) |
+ ty::Never |
+ ty::Foreign(..) => false,
}
}
_ => false,
}
}
+
+ /// When canonicalizing, we replace unbound inference variables and free
+ /// regions with anonymous late bound regions. This method asserts that
+ /// we have an anonymous late bound region, which hence may refer to
+ /// a canonical variable.
+ pub fn assert_bound_var(&self) -> BoundVar {
+ match *self {
+ BoundRegion::BrAnon(var) => BoundVar::from_u32(var),
+ _ => bug!("bound region is not anonymous"),
+ }
+ }
}
/// N.B., If you change this, you'll probably want to change the corresponding
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}
Param(ParamTy),
+ /// Bound type variable, used only when preparing a trait query.
+ Bound(BoundTy),
+
/// A type variable used during type checking.
Infer(InferTy),
TraitRef { def_id: def_id, substs: substs }
}
- /// Returns a TraitRef of the form `P0: Foo<P1..Pn>` where `Pi`
+ /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
/// are the parameters defined on trait.
pub fn identity<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> TraitRef<'tcx> {
TraitRef {
/// or some placeholder type.
pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
-> ty::TraitRef<'tcx> {
- // otherwise the escaping regions would be captured by the binder
- // debug_assert!(!self_ty.has_escaping_regions());
+ // otherwise the escaping vars would be captured by the binder
+ // debug_assert!(!self_ty.has_escaping_bound_vars());
ty::TraitRef {
def_id: self.def_id,
}
}
-/// Binder is a binder for higher-ranked lifetimes. It is part of the
+/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
/// (which would be represented by the type `PolyTraitRef ==
/// Binder<TraitRef>`). Note that when we instantiate,
-/// erase, or otherwise "discharge" these bound regions, we change the
+/// erase, or otherwise "discharge" these bound vars, we change the
/// type from `Binder<T>` to just `T` (see
/// e.g. `liberate_late_bound_regions`).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
impl<T> Binder<T> {
/// Wraps `value` in a binder, asserting that `value` does not
- /// contain any bound regions that would be bound by the
+ /// contain any bound vars that would be bound by the
/// binder. This is commonly used to 'inject' a value T into a
/// different binding level.
pub fn dummy<'tcx>(value: T) -> Binder<T>
where T: TypeFoldable<'tcx>
{
- debug_assert!(!value.has_escaping_regions());
+ debug_assert!(!value.has_escaping_bound_vars());
Binder(value)
}
- /// Wraps `value` in a binder, binding late-bound regions (if any).
- pub fn bind<'tcx>(value: T) -> Binder<T>
- {
+ /// Wraps `value` in a binder, binding higher-ranked vars (if any).
+ pub fn bind<'tcx>(value: T) -> Binder<T> {
Binder(value)
}
/// Skips the binder and returns the "bound" value. This is a
/// risky thing to do because it's easy to get confused about
/// debruijn indices and the like. It is usually better to
- /// discharge the binder using `no_late_bound_regions` or
+ /// discharge the binder using `no_bound_vars` or
/// `replace_late_bound_regions` or something like
/// that. `skip_binder` is only valid when you are either
- /// extracting data that has nothing to do with bound regions, you
+ /// extracting data that has nothing to do with bound vars, you
/// are doing some sort of test that does not involve bound
/// regions, or you are being very careful about your depth
/// accounting.
///
/// - extracting the def-id from a PolyTraitRef;
/// - comparing the self type of a PolyTraitRef to see if it is equal to
- /// a type parameter `X`, since the type `X` does not reference any regions
+ /// a type parameter `X`, since the type `X` does not reference any regions
pub fn skip_binder(&self) -> &T {
&self.0
}
}
/// Unwraps and returns the value within, but only if it contains
- /// no bound regions at all. (In other words, if this binder --
+ /// no bound vars at all. (In other words, if this binder --
/// and indeed any enclosing binder -- doesn't bind anything at
/// all.) Otherwise, returns `None`.
///
/// (One could imagine having a method that just unwraps a single
- /// binder, but permits late-bound regions bound by enclosing
+ /// binder, but permits late-bound vars bound by enclosing
/// binders, but that would require adjusting the debruijn
/// indices, and given the shallow binding structure we often use,
/// would not be that useful.)
- pub fn no_late_bound_regions<'tcx>(self) -> Option<T>
- where T : TypeFoldable<'tcx>
+ pub fn no_bound_vars<'tcx>(self) -> Option<T>
+ where T: TypeFoldable<'tcx>
{
- if self.skip_binder().has_escaping_regions() {
+ if self.skip_binder().has_escaping_bound_vars() {
None
} else {
Some(self.skip_binder().clone())
/// `ClosureRegionRequirements` that are produced by MIR borrowck.
/// See `ClosureRegionRequirements` for more details.
ReClosureBound(RegionVid),
-
- /// Canonicalized region, used only when preparing a trait query.
- ReCanonical(BoundTyIndex),
}
impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
FreshTy(u32),
FreshIntTy(u32),
FreshFloatTy(u32),
-
- /// Bound type variable, used only when preparing a trait query.
- BoundTy(BoundTy),
}
newtype_index! {
- pub struct BoundTyIndex { .. }
+ pub struct BoundVar { .. }
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct BoundTy {
- pub level: DebruijnIndex,
- pub var: BoundTyIndex,
+ pub index: DebruijnIndex,
+ pub var: BoundVar,
+ pub kind: BoundTyKind,
}
-impl_stable_hash_for!(struct BoundTy { level, var });
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+pub enum BoundTyKind {
+ Anon,
+ Param(InternedString),
+}
+
+impl_stable_hash_for!(struct BoundTy { index, var, kind });
+impl_stable_hash_for!(enum self::BoundTyKind { Anon, Param(a) });
+
+impl BoundTy {
+ pub fn new(index: DebruijnIndex, var: BoundVar) -> Self {
+ BoundTy {
+ index,
+ var,
+ kind: BoundTyKind::Anon,
+ }
+ }
+}
/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-> ty::ProjectionPredicate<'tcx>
{
// otherwise the escaping regions would be captured by the binders
- debug_assert!(!self_ty.has_escaping_regions());
+ debug_assert!(!self_ty.has_escaping_bound_vars());
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
RegionKind::ReEmpty => false,
RegionKind::ReErased => false,
RegionKind::ReClosureBound(..) => false,
- RegionKind::ReCanonical(..) => false,
}
}
}
ty::ReErased => {
}
- ty::ReCanonical(..) => {
- flags = flags | TypeFlags::HAS_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_CANONICAL_VARS;
- }
ty::ReClosureBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
Tuple(..) |
Foreign(..) |
Param(_) |
+ Bound(..) |
Infer(_) |
Error => {
vec![]
ty::Infer(ty::TyVar(_)) => false,
- ty::Infer(ty::BoundTy(_)) |
+ ty::Bound(_) |
ty::Infer(ty::FreshTy(_)) |
ty::Infer(ty::FreshIntTy(_)) |
ty::Infer(ty::FreshFloatTy(_)) =>
use hir::def_id::DefId;
use infer::canonical::Canonical;
-use ty::{self, BoundTyIndex, Lift, List, Ty, TyCtxt};
+use ty::{self, BoundVar, Lift, List, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
span,
root_ty: None,
ty_stack_depth: 0,
- region_binders_passed: 0 };
+ binders_passed: 0 };
(*self).fold_with(&mut folder)
}
}
ty_stack_depth: usize,
// Number of region binders we have passed through while doing the substitution
- region_binders_passed: u32,
+ binders_passed: u32,
}
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
- self.region_binders_passed += 1;
+ self.binders_passed += 1;
let t = t.super_fold_with(self);
- self.region_binders_passed -= 1;
+ self.binders_passed -= 1;
t
}
}
};
- self.shift_regions_through_binders(ty)
+ self.shift_vars_through_binders(ty)
}
/// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs
- /// when we are substituting a type with escaping regions into a context where we have passed
- /// through region binders. That's quite a mouthful. Let's see an example:
+ /// when we are substituting a type with escaping bound vars into a context where we have
+ /// passed through binders. That's quite a mouthful. Let's see an example:
///
/// ```
/// type Func<A> = fn(A);
/// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
/// first case we do not increase the Debruijn index and in the second case we do. The reason
/// is that only in the second case have we passed through a fn binder.
- fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
- debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})",
- ty, self.region_binders_passed, ty.has_escaping_regions());
+ fn shift_vars_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ debug!("shift_vars(ty={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})",
+ ty, self.binders_passed, ty.has_escaping_bound_vars());
- if self.region_binders_passed == 0 || !ty.has_escaping_regions() {
+ if self.binders_passed == 0 || !ty.has_escaping_bound_vars() {
return ty;
}
- let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
- debug!("shift_regions: shifted result = {:?}", result);
+ let result = ty::fold::shift_vars(self.tcx(), &ty, self.binders_passed);
+ debug!("shift_vars: shifted result = {:?}", result);
result
}
fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> {
- if self.region_binders_passed == 0 || !region.has_escaping_regions() {
+ if self.binders_passed == 0 || !region.has_escaping_bound_vars() {
return region;
}
- self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
+ ty::fold::shift_region(self.tcx, region, self.binders_passed)
}
}
return false;
}
- self.value.substs.iter().zip(BoundTyIndex::new(0)..).all(|(kind, cvar)| {
+ self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| {
match kind.unpack() {
UnpackedKind::Type(ty) => match ty.sty {
- ty::Infer(ty::BoundTy(ref b)) => cvar == b.var,
+ ty::Bound(b) => {
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(b.index, ty::INNERMOST);
+ cvar == b.var
+ }
_ => false,
},
UnpackedKind::Lifetime(r) => match r {
- ty::ReCanonical(cvar1) => cvar == *cvar1,
+ ty::ReLateBound(index, br) => {
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(*index, ty::INNERMOST);
+ cvar == br.assert_bound_var()
+ }
_ => false,
},
}
erased_self_ty,
predicates);
- assert!(!erased_self_ty.has_escaping_regions());
+ assert!(!erased_self_ty.has_escaping_bound_vars());
traits::elaborate_predicates(self, predicates)
.filter_map(|predicate| {
// construct such an object, but this seems
// correct even if that code changes).
let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
- if t == &erased_self_ty && !r.has_escaping_regions() {
+ if t == &erased_self_ty && !r.has_escaping_bound_vars() {
Some(*r)
} else {
None
self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr
}
- /// True if `def_id` refers to a trait (e.g., `trait Foo { ... }`).
+ /// True if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
pub fn is_trait(self, def_id: DefId) -> bool {
if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data {
true
// Can refer to a type which may drop.
// FIXME(eddyb) check this against a ParamEnv.
- ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) |
+ ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) |
ty::Opaque(..) | ty::Infer(_) | ty::Error => true,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
match parent_ty.sty {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) |
ty::Str | ty::Infer(_) | ty::Param(_) | ty::Never | ty::Error |
- ty::Foreign(..) => {
+ ty::Bound(..) | ty::Foreign(..) => {
}
ty::Array(ty, len) => {
push_const(stack, len);
let infcx = &mut self.infcx;
let param_env = self.param_env;
self.out.iter()
- .inspect(|pred| assert!(!pred.has_escaping_regions()))
+ .inspect(|pred| assert!(!pred.has_escaping_bound_vars()))
.flat_map(|pred| {
let mut selcx = traits::SelectionContext::new(infcx);
let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred);
self.out.extend(
trait_ref.substs.types()
- .filter(|ty| !ty.has_escaping_regions())
+ .filter(|ty| !ty.has_escaping_bound_vars())
.map(|ty| traits::Obligation::new(cause.clone(),
param_env,
ty::Predicate::WellFormed(ty))));
let trait_ref = data.trait_ref(self.infcx.tcx);
self.compute_trait_ref(&trait_ref, Elaborate::None);
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
let predicate = trait_ref.to_predicate();
let cause = self.cause(traits::ProjectionWf(data));
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
}
fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
- if !subty.has_escaping_regions() {
+ if !subty.has_escaping_bound_vars() {
let cause = self.cause(cause);
let trait_ref = ty::TraitRef {
def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
ty::GeneratorWitness(..) |
ty::Never |
ty::Param(_) |
+ ty::Bound(..) |
ty::Foreign(..) => {
// WfScalar, WfParameter, etc
}
ty::Ref(r, rty, _) => {
// WfReference
- if !r.has_escaping_regions() && !rty.has_escaping_regions() {
+ if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
self.out.push(
traits::Obligation::new(
.map(|pred| traits::Obligation::new(cause.clone(),
self.param_env,
pred))
- .filter(|pred| !pred.has_escaping_regions())
+ .filter(|pred| !pred.has_escaping_bound_vars())
.collect()
}
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
// am looking forward to the future here.
- if !data.has_escaping_regions() {
+ if !data.has_escaping_bound_vars() {
let implicit_bounds =
object_region_bounds(self.infcx.tcx, data);
use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
use ty::{Bool, Char, Adt};
use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
-use ty::{Param, RawPtr, Ref, Never, Tuple};
+use ty::{Param, Bound, RawPtr, Ref, Never, Tuple};
use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
use ty::{UnnormalizedProjection, Dynamic, Int, Uint, Infer};
use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
ty::ReEarlyBound(ref data) => {
write!(f, "{}", data.name)
}
- ty::ReCanonical(_) => {
- write!(f, "'_")
- }
ty::ReLateBound(_, br) |
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
write!(f, "{:?}", vid)
}
- ty::ReCanonical(c) => {
- write!(f, "'?{}", c.index())
- }
-
ty::RePlaceholder(placeholder) => {
write!(f, "RePlaceholder({:?})", placeholder)
}
ty::TyVar(_) => write!(f, "_"),
ty::IntVar(_) => write!(f, "{}", "{integer}"),
ty::FloatVar(_) => write!(f, "{}", "{float}"),
- ty::BoundTy(_) => write!(f, "_"),
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
ty::TyVar(ref v) => write!(f, "{:?}", v),
ty::IntVar(ref v) => write!(f, "{:?}", v),
ty::FloatVar(ref v) => write!(f, "{:?}", v),
- ty::BoundTy(v) => write!(f, "?{:?}", v.var.index()),
ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
Infer(infer_ty) => write!(f, "{}", infer_ty),
Error => write!(f, "[type error]"),
Param(ref param_ty) => write!(f, "{}", param_ty),
+ Bound(bound_ty) => {
+ match bound_ty.kind {
+ ty::BoundTyKind::Anon => {
+ if bound_ty.index == ty::INNERMOST {
+ write!(f, "?{}", bound_ty.var.index())
+ } else {
+ write!(f, "?{}_{}", bound_ty.index.index(), bound_ty.var.index())
+ }
+ }
+
+ ty::BoundTyKind::Param(p) => write!(f, "{}", p),
+ }
+ }
Adt(def, substs) => cx.parameterized(f, substs, def.did, &[]),
Dynamic(data, r) => {
let r = r.print_to_string(cx);
// These cannot exist in borrowck
RegionKind::ReVar(..) |
- RegionKind::ReCanonical(..) |
RegionKind::RePlaceholder(..) |
RegionKind::ReClosureBound(..) |
RegionKind::ReErased => span_bug!(borrow_span,
ty::ReStatic => self.item_ub,
- ty::ReCanonical(_) |
ty::ReEmpty |
ty::ReClosureBound(..) |
ty::ReLateBound(..) |
// regions must appear in the argument
// listing.
let main_ret_ty = cx.tcx.erase_regions(
- &main_ret_ty.no_late_bound_regions().unwrap(),
+ &main_ret_ty.no_bound_vars().unwrap(),
);
if declare::get_defined_value(cx, "main").is_some() {
debug!("get_fn(instance={:?})", instance);
assert!(!instance.substs.needs_infer());
- assert!(!instance.substs.has_escaping_regions());
+ assert!(!instance.substs.has_escaping_bound_vars());
assert!(!instance.substs.has_param_types());
let sig = instance.fn_sig(cx.tcx);
ty::Infer(_) |
ty::UnnormalizedProjection(..) |
ty::Projection(..) |
+ ty::Bound(..) |
ty::Opaque(..) |
ty::GeneratorWitness(..) |
ty::Param(_) => {
debug!("llvm_type({:#?})", self);
- assert!(!self.ty.has_escaping_regions(), "{:?} has escaping regions", self.ty);
+ assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
// Make sure lifetimes are erased, to avoid generating distinct LLVM
// types for Rust types that only differ in the choice of lifetimes.
// Theta = [A -> &'a foo]
env.create_simple_region_hierarchy();
- assert!(!env.t_nil().has_escaping_regions());
+ assert!(!env.t_nil().has_escaping_bound_vars());
let t_rptr_free1 = env.t_rptr_free(1);
- assert!(!t_rptr_free1.has_escaping_regions());
+ assert!(!t_rptr_free1.has_escaping_bound_vars());
let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, d1());
- assert!(t_rptr_bound1.has_escaping_regions());
+ assert!(t_rptr_bound1.has_escaping_bound_vars());
let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, d2());
- assert!(t_rptr_bound2.has_escaping_regions());
+ assert!(t_rptr_bound2.has_escaping_bound_vars());
// t_fn = fn(A)
let t_param = env.t_param(0);
- assert!(!t_param.has_escaping_regions());
+ assert!(!t_param.has_escaping_bound_vars());
let t_fn = env.t_fn(&[t_param], env.t_nil());
- assert!(!t_fn.has_escaping_regions());
+ assert!(!t_fn.has_escaping_bound_vars());
})
}
ty::Param(..) |
ty::Infer(..) |
+ ty::Bound(..) |
ty::Error |
ty::Closure(..) |
ty::Generator(..) |
for (i, dep) in root.crate_deps
.decode(self)
.enumerate() {
- write!(out, "{} {}-{}\n", i + 1, dep.name, dep.hash)?;
+ write!(out, "{} {}{}\n", i + 1, dep.name, dep.extra_filename)?;
}
write!(out, "\n")?;
Ok(())
| ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReErased
- | ty::ReClosureBound(..)
- | ty::ReCanonical(..) => None,
+ | ty::ReClosureBound(..) => None,
}
}
// when we move to universes, we will, and this assertion
// will start to fail.
let ty::OutlivesPredicate(k1, r2) =
- query_constraint.no_late_bound_regions().unwrap_or_else(|| {
+ query_constraint.no_bound_vars().unwrap_or_else(|| {
bug!(
- "query_constraint {:?} contained bound regions",
+ "query_constraint {:?} contained bound vars",
query_constraint,
);
});
}
fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.has_escaping_regions() || ty.references_error() {
+ if ty.has_escaping_bound_vars() || ty.references_error() {
span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
} else {
ty
.enumerate()
.filter_map(|(idx, constraint)| {
let ty::OutlivesPredicate(k1, r2) =
- constraint.no_late_bound_regions().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound regions", constraint,);
+ constraint.no_bound_vars().unwrap_or_else(|| {
+ bug!("query_constraint {:?} contained bound vars", constraint,);
});
match k1.unpack() {
trait_ty: Ty<'tcx>,
impl_ty: Ty<'tcx>,
output: &mut Vec<MonoItem<'tcx>>) {
- assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_regions() &&
- !impl_ty.needs_subst() && !impl_ty.has_escaping_regions());
+ assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_bound_vars() &&
+ !impl_ty.needs_subst() && !impl_ty.has_escaping_bound_vars());
if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty {
let poly_trait_ref = trait_ty.principal().with_self_ty(tcx, impl_ty);
- assert!(!poly_trait_ref.has_escaping_regions());
+ assert!(!poly_trait_ref.has_escaping_bound_vars());
// Walk all methods of the trait, including those of its supertraits
let methods = tcx.vtable_methods(poly_trait_ref);
// regions must appear in the argument
// listing.
let main_ret_ty = self.tcx.erase_regions(
- &main_ret_ty.no_late_bound_regions().unwrap(),
+ &main_ret_ty.no_bound_vars().unwrap(),
);
let start_instance = Instance::resolve(
self.push_type_params(substs, iter::empty(), output);
}
ty::Error |
+ ty::Bound(..) |
ty::Infer(_) |
ty::UnnormalizedProjection(..) |
ty::Projection(..) |
let param_env = gcx.param_env(def_id);
// Normalize the sig.
- let sig = gcx.fn_sig(def_id).no_late_bound_regions().expect("LBR in ADT constructor signature");
+ let sig = gcx.fn_sig(def_id)
+ .no_bound_vars()
+ .expect("LBR in ADT constructor signature");
let sig = gcx.normalize_erasing_regions(param_env, sig);
let (adt_def, substs) = match sig.output().sty {
{
let did = tcx.require_lang_item(lang_item);
let poly_sig = tcx.fn_sig(did);
- let sig = poly_sig.no_late_bound_regions().unwrap();
+ let sig = poly_sig.no_bound_vars().unwrap();
let lhs_ty = lhs.ty(local_decls, tcx);
let rhs_ty = rhs.ty(local_decls, tcx);
let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
}
}
}
- ItemKind::TraitAlias(Generics { ref params, .. }, ..) => {
- for param in params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {}
- GenericParamKind::Type { ref default, .. } => {
- if !param.bounds.is_empty() {
- self.err_handler()
- .span_err(param.ident.span, "type parameters on the left \
- side of a trait alias cannot be bounded");
- }
- if !default.is_none() {
- self.err_handler()
- .span_err(param.ident.span, "type parameters on the left \
- side of a trait alias cannot have defaults");
- }
- }
- }
- }
- }
ItemKind::Mod(_) => {
// Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
attr::first_attr_value_str_by_name(&item.attrs, "path");
match self {
PathSource::Type => match def {
Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
- Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
- Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) |
- Def::Existential(..) |
+ Def::Trait(..) | Def::TraitAlias(..) | Def::TyAlias(..) |
+ Def::AssociatedTy(..) | Def::PrimTy(..) | Def::TyParam(..) |
+ Def::SelfTy(..) | Def::Existential(..) |
Def::ForeignTy(..) => true,
_ => false,
},
return (err, candidates);
}
(Def::TyAlias(..), PathSource::Trait(_)) => {
- err.span_label(span, "type aliases cannot be used for traits");
+ err.span_label(span, "type aliases cannot be used as traits");
+ if nightly_options::is_nightly_build() {
+ err.note("did you mean to use a trait alias?");
+ }
return (err, candidates);
}
(Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
// report an error.
if record_used {
resolve_error(self, span,
- ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
+ ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
}
return Def::Err;
}
// Still doesn't deal with upvars
if record_used {
resolve_error(self, span,
- ResolutionError::AttemptToUseNonConstantValueInConstant);
+ ResolutionError::AttemptToUseNonConstantValueInConstant);
}
return Def::Err;
}
ty::GeneratorWitness(..) |
ty::UnnormalizedProjection(..) |
ty::Infer(..) |
+ ty::Bound(..) |
ty::Error => {
bug!("unexpected type {:?}", ty)
}
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
- ty::Infer(..) | ty::Error => {
+ ty::Bound(..) | ty::Infer(..) | ty::Error => {
// By the time this code runs, all type variables ought to
// be fully resolved.
Err(NoSolution)
// From the full set of obligations, just filter down to the
// region relationships.
implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
- assert!(!obligation.has_escaping_regions());
+ assert!(!obligation.has_escaping_bound_vars());
match obligation.predicate {
ty::Predicate::Trait(..) |
ty::Predicate::Subtype(..) |
vec![]
}
- ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() {
+ ty::Predicate::RegionOutlives(ref data) => match data.no_bound_vars() {
None => vec![],
Some(ty::OutlivesPredicate(r_a, r_b)) => {
vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
}
},
- ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() {
+ ty::Predicate::TypeOutlives(ref data) => match data.no_bound_vars() {
None => vec![],
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
let ty_a = infcx.resolve_type_vars_if_possible(&ty_a);
ty::GeneratorWitness(..) |
ty::UnnormalizedProjection(..) |
ty::Infer(..) |
+ ty::Bound(..) |
ty::Error => {
bug!("unexpected type {:?}", ty);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Conversion from AST representation of types to the ty.rs
+//! Conversion from AST representation of types to the `ty.rs`
//! representation. The main routine here is `ast_ty_to_ty()`: each use
//! is parameterized by an instance of `AstConv`.
item_segment: &hir::PathSegment)
-> &'tcx Substs<'tcx>
{
-
let (substs, assoc_bindings) = item_segment.with_generic_args(|generic_args| {
self.create_substs_for_ast_path(
span,
}
/// Given the type/region 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.
///
/// Note that the type listing given here is *exactly* what the user provided.
{
let trait_def_id = self.trait_def_id(trait_ref);
- debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
+ debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
let predicate: Result<_, ErrorReported> =
self.ast_type_binding_to_poly_projection_predicate(
trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
- // ok to ignore Err() because ErrorReported (see above)
+ // ok to ignore Err because ErrorReported (see above)
Some((predicate.ok()?, binding.span))
}));
- debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}",
+ debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
trait_ref, poly_projections, poly_trait_ref);
poly_trait_ref
}
)
}
- /// Transform a PolyTraitRef into a PolyExistentialTraitRef by
- /// removing the dummy Self type (TRAIT_OBJECT_DUMMY_SELF).
+ /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
+ /// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`).
fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>)
-> ty::ExistentialTraitRef<'tcx> {
assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF);
let principal = self.instantiate_poly_trait_ref(&trait_bounds[0],
dummy_self,
&mut projection_bounds);
+ debug!("principal: {:?}", principal);
for trait_bound in trait_bounds[1..].iter() {
- // Sanity check for non-principal trait bounds
+ // sanity check for non-principal trait bounds
self.instantiate_poly_trait_ref(trait_bound,
dummy_self,
&mut vec![]);
})
});
- // check that there are no gross object safety violations,
+ // Check that there are no gross object safety violations;
// most importantly, that the supertraits don't contain Self,
- // to avoid ICE-s.
+ // to avoid ICEs.
let object_safety_violations =
tcx.global_tcx().astconv_object_safety_violations(principal.def_id());
if !object_safety_violations.is_empty() {
return tcx.types.err;
}
- // use a btreeset to keep output in a more consistent order
+ // Use a BTreeSet to keep output in a more consistent order.
let mut associated_types = BTreeSet::default();
for tr in traits::supertraits(tcx, principal) {
v.sort_by(|a, b| a.stable_cmp(tcx, b));
let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter()));
- // Explicitly specified region bound. Use that.
+ // Use explicitly-specified region bound.
let region_bound = if !lifetime.is_elided() {
self.ast_region_to_region(lifetime, None)
} else {
err.span_label(span, "associated type not allowed here").emit();
}
- // Check a type Path and convert it to a Ty.
+ // Check a type `Path` and convert it to a `Ty`.
pub fn def_to_ty(&self,
opt_self_ty: Option<Ty<'tcx>>,
path: &hir::Path,
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
- debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})",
- ast_ty.id, ast_ty);
+ debug!("ast_ty_to_ty(id={:?}, ast_ty={:?} ty_ty={:?})",
+ ast_ty.id, ast_ty, ast_ty.node);
let tcx = self.tcx();
self.region_bounds.iter().map(|&(region_bound, span)| {
// account for the binder being introduced below; no need to shift `param_ty`
// because, at present at least, it can only refer to early-bound regions
- let region_bound = tcx.mk_region(ty::fold::shift_region(*region_bound, 1));
+ let region_bound = ty::fold::shift_region(tcx, region_bound, 1);
let outlives = ty::OutlivesPredicate(param_ty, region_bound);
(ty::Binder::dummy(outlives).to_predicate(), span)
}).chain(
}
// Replace constructor type with constructed type for tuple struct patterns.
let pat_ty = pat_ty.fn_sig(tcx).output();
- let pat_ty = pat_ty.no_late_bound_regions().expect("expected fn type");
+ let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
self.demand_eqtype(pat.span, expected, pat_ty);
ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)),
ty::Param(ref p) => Some(PointerKind::OfParam(p)),
// Insufficient type information.
- ty::Infer(_) => None,
+ ty::Bound(..) | ty::Infer(_) => None,
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
ty::Float(_) | ty::Array(..) | ty::GeneratorWitness(..) |
// Create a `PolyFnSig`. Note the oddity that late bound
// regions appearing free in `expected_sig` are now bound up
// in this binder we are creating.
- assert!(!expected_sig.sig.has_regions_bound_above(ty::INNERMOST));
+ assert!(!expected_sig.sig.has_vars_bound_above(ty::INNERMOST));
let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig(
expected_sig.sig.inputs().iter().cloned(),
expected_sig.sig.output(),
let mut structural_to_nomimal = FxHashMap::default();
let sig = tcx.fn_sig(def_id);
- let sig = sig.no_late_bound_regions().unwrap();
+ let sig = sig.no_bound_vars().unwrap();
if intr.inputs.len() != sig.inputs().len() {
span_err!(tcx.sess, it.span, E0444,
"platform-specific intrinsic has invalid number of \
value
}
};
- assert!(!bounds.has_escaping_regions());
+ assert!(!bounds.has_escaping_bound_vars());
let cause = traits::ObligationCause::misc(span, self.body_id);
obligations.extend(traits::predicates_for_generics(cause.clone(),
fn_sig,
substs);
- assert!(!substs.has_escaping_regions());
+ assert!(!substs.has_escaping_bound_vars());
// It is possible for type parameters or early-bound lifetimes
// to appear in the signature of `self`. The substitutions we
fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
debug!("register_predicate({:?})", obligation);
- if obligation.has_escaping_regions() {
- span_bug!(obligation.cause.span, "escaping regions in predicate {:?}",
+ if obligation.has_escaping_bound_vars() {
+ span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}",
obligation);
}
self.fulfillment_cx
}
fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.has_escaping_regions() {
+ if ty.has_escaping_bound_vars() {
ty // FIXME: normalization and escaping regions
} else {
self.normalize_associated_types_in(span, &ty)
cause: traits::ObligationCause<'tcx>,
predicates: &ty::InstantiatedPredicates<'tcx>)
{
- assert!(!predicates.has_escaping_regions());
+ assert!(!predicates.has_escaping_bound_vars());
debug!("add_obligations_for_parameters(predicates={:?})",
predicates);
}
},
);
- assert!(!substs.has_escaping_regions());
- assert!(!ty.has_escaping_regions());
+ assert!(!substs.has_escaping_bound_vars());
+ assert!(!ty.has_escaping_bound_vars());
// Write the "user substs" down first thing for later.
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
hir::ItemKind::Trait(..) => {
check_trait(tcx, item);
}
+ hir::ItemKind::TraitAlias(..) => {
+ check_trait(tcx, item);
+ }
_ => {}
}
}
let span = tcx.hir.span(impl_node_id);
let param_env = tcx.param_env(impl_did);
- assert!(!self_type.has_escaping_regions());
+ assert!(!self_type.has_escaping_bound_vars());
debug!("visit_implementation_of_copy: self_type={:?} (free)",
self_type);
let span = tcx.hir.span(impl_node_id);
let source = tcx.type_of(impl_did);
- assert!(!source.has_escaping_regions());
+ assert!(!source.has_escaping_bound_vars());
let target = {
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
let span = gcx.hir.span(impl_node_id);
let param_env = gcx.param_env(impl_did);
- assert!(!source.has_escaping_regions());
+ assert!(!source.has_escaping_bound_vars());
let err_info = CoerceUnsizedInfo { custom_kind: None };
use std::iter;
+struct OnlySelfBounds(bool);
+
///////////////////////////////////////////////////////////////////////////
// Main entry point
item_def_id: DefId,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
- if let Some(trait_ref) = poly_trait_ref.no_late_bound_regions() {
+ if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
self.tcx().mk_projection(item_def_id, trait_ref.substs)
} else {
// no late-bound regions, we can just ignore the binder
use rustc::hir::*;
// In the AST, bounds can derive from two places. Either
- // written inline like `<T:Foo>` or in a where clause like
- // `where T:Foo`.
+ // written inline like `<T : Foo>` or in a where clause like
+ // `where T : Foo`.
let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
let param_owner = tcx.hir.ty_param_owner(param_id);
let icx = ItemCtxt::new(tcx, item_def_id);
result
.predicates
- .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
+ .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty,
+ OnlySelfBounds(true)));
result
}
impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
- /// Find bounds from hir::Generics. This requires scanning through the
+ /// Find bounds from `hir::Generics`. This requires scanning through the
/// AST. We do this to avoid having to convert *all* the bounds, which
/// would create artificial cycles. Instead we can only convert the
/// bounds for a type parameter `X` if `X::Foo` is used.
ast_generics: &hir::Generics,
param_id: ast::NodeId,
ty: Ty<'tcx>,
+ only_self_bounds: OnlySelfBounds,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let from_ty_params = ast_generics
.params
hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
_ => None,
})
- .filter(|bp| is_param(self.tcx, &bp.bounded_ty, param_id))
- .flat_map(|bp| bp.bounds.iter())
- .flat_map(|b| predicates_from_bound(self, ty, b));
+ .flat_map(|bp| {
+ let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) {
+ Some(ty)
+ } else if !only_self_bounds.0 {
+ Some(self.to_ty(&bp.bounded_ty))
+ } else {
+ None
+ };
+ bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b)))
+ })
+ .flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
from_ty_params.chain(from_where_clauses).collect()
}
tcx.predicates_of(def_id);
}
hir::ItemKind::TraitAlias(..) => {
- span_err!(
- tcx.sess,
- it.span,
- E0645,
- "trait aliases are not yet implemented (see issue #41517)"
- );
+ tcx.generics_of(def_id);
+ tcx.at(it.span).super_predicates_of(def_id);
+ tcx.predicates_of(def_id);
}
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
tcx.generics_of(def_id);
let icx = ItemCtxt::new(tcx, trait_def_id);
- // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
+ // 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 = superbounds1.predicates(tcx, self_param_ty);
// Convert any explicit superbounds in the where clause,
- // e.g. `trait Foo where Self : Bar`:
- let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty);
+ // e.g. `trait Foo where Self : Bar`.
+ // In the case of trait aliases, however, we include all bounds in the where clause,
+ // so e.g. `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+ // as one of its "superpredicates".
+ let is_trait_alias = ty::is_trait_alias(tcx, trait_def_id);
+ let superbounds2 = icx.type_parameter_bounds_in_generics(
+ generics, item.id, self_param_ty, OnlySelfBounds(!is_trait_alias));
// Combine the two lists to form the complete set of superbounds:
let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect();
// Now require that immediate supertraits are converted,
// which will, in turn, reach indirect supertraits.
for &(pred, span) in &superbounds {
+ debug!("superbound: {:?}", pred);
if let ty::Predicate::Trait(bound) = pred {
tcx.at(span).super_predicates_of(bound.def_id());
}
let icx = ItemCtxt::new(tcx, def_id);
let no_generics = hir::Generics::empty();
+ let empty_trait_items = HirVec::new();
let mut predicates = UniquePredicates::new();
is_trait = Some((ty::TraitRef::identity(tcx, def_id), items));
generics
}
+ ItemKind::TraitAlias(ref generics, _) => {
+ is_trait = Some((ty::TraitRef::identity(tcx, def_id), &empty_trait_items));
+ generics
+ }
ItemKind::Existential(ExistTy {
ref bounds,
impl_trait_fn,
}
}
-/// Converts a specific GenericBound from the AST into a set of
+/// 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 0 predicates (`T:?Sized` adds no
-/// predicates) to 1 (`T:Foo`) to many (`T:Bar<X=i32>` adds `T:Bar`
+/// because this can be anywhere from zero predicates (`T : ?Sized` adds no
+/// predicates) to one (`T : Foo`) to many (`T : Bar<X=i32>` adds `T : Bar`
/// and `<T as Bar>::X == i32`).
fn predicates_from_bound<'tcx>(
astconv: &dyn AstConv<'tcx, 'tcx>,
RegionKind::ReEmpty
| RegionKind::ReErased
| RegionKind::ReClosureBound(..)
- | RegionKind::ReCanonical(..)
| RegionKind::ReScope(..)
| RegionKind::ReVar(..)
| RegionKind::RePlaceholder(..)
ty::UnnormalizedProjection(..) |
ty::GeneratorWitness(..) |
+ ty::Bound(..) |
ty::Infer(..) => {
bug!("unexpected type encountered in \
variance inference: {}",
// way early-bound regions do, so we skip them here.
}
- ty::ReCanonical(_) |
ty::ReFree(..) |
ty::ReClosureBound(..) |
ty::ReScope(..) |
_ => return None,
})
}
+
+ pub fn is_associated(&self) -> bool {
+ match *self {
+ ItemEnum::TypedefItem(_, _) |
+ ItemEnum::AssociatedTypeItem(_, _) => true,
+ _ => false,
+ }
+ }
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
ty::RePlaceholder(..) |
ty::ReEmpty |
ty::ReClosureBound(_) |
- ty::ReCanonical(_) |
ty::ReErased => None
}
}
ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
+ ty::Bound(..) => panic!("Bound"),
ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::Infer(..) => panic!("Infer"),
if let Some(ref name) = item.name {
info!("Documenting {}", name);
}
- document_stability(w, cx, item)?;
- document_full(w, item, cx, "")?;
+ document_stability(w, cx, item, false)?;
+ document_full(w, item, cx, "", false)?;
Ok(())
}
cx: &Context,
md_text: &str,
links: Vec<(String, String)>,
- prefix: &str)
+ prefix: &str,
+ is_hidden: bool)
-> fmt::Result {
let mut ids = cx.id_map.borrow_mut();
- write!(w, "<div class='docblock'>{}{}</div>",
- prefix, Markdown(md_text, &links, RefCell::new(&mut ids), cx.codes))
+ write!(w, "<div class='docblock{}'>{}{}</div>",
+ if is_hidden { " hidden" } else { "" },
+ prefix,
+ Markdown(md_text, &links, RefCell::new(&mut ids),
+ cx.codes))
}
fn document_short(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, link: AssocItemLink,
- prefix: &str) -> fmt::Result {
+ prefix: &str, is_hidden: bool) -> fmt::Result {
if let Some(s) = item.doc_value() {
let markdown = if s.contains('\n') {
format!("{} [Read more]({})",
} else {
plain_summary_line(Some(s))
};
- render_markdown(w, cx, &markdown, item.links(), prefix)?;
+ render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden)?;
} else if !prefix.is_empty() {
- write!(w, "<div class='docblock'>{}</div>", prefix)?;
+ write!(w, "<div class='docblock{}'>{}</div>",
+ if is_hidden { " hidden" } else { "" },
+ prefix)?;
}
Ok(())
}
fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
- cx: &Context, prefix: &str) -> fmt::Result {
+ cx: &Context, prefix: &str, is_hidden: bool) -> fmt::Result {
if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
debug!("Doc block: =====\n{}\n=====", s);
- render_markdown(w, cx, &*s, item.links(), prefix)?;
+ render_markdown(w, cx, &*s, item.links(), prefix, is_hidden)?;
} else if !prefix.is_empty() {
- write!(w, "<div class='docblock'>{}</div>", prefix)?;
+ write!(w, "<div class='docblock{}'>{}</div>",
+ if is_hidden { " hidden" } else { "" },
+ prefix)?;
}
Ok(())
}
-fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
+fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
+ is_hidden: bool) -> fmt::Result {
let stabilities = short_stability(item, cx, true);
if !stabilities.is_empty() {
- write!(w, "<div class='stability'>")?;
+ write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" })?;
for stability in stabilities {
write!(w, "{}", stability)?;
}
RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
};
+ let (is_hidden, extra_class) = if trait_.is_none() ||
+ item.doc_value().is_some() ||
+ item.inner.is_associated() {
+ (false, "")
+ } else {
+ (true, " hidden")
+ };
match item.inner {
clean::MethodItem(clean::Method { ref decl, .. }) |
- clean::TyMethodItem(clean::TyMethod{ ref decl, .. }) => {
+ clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => {
// Only render when the method is not static or we allow static methods
if render_method_item {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "{}", spotlight_decl(decl)?)?;
write!(w, "<span id='{}' class='invisible'>", ns_id)?;
write!(w, "<table class='table-display'><tbody><tr><td><code>")?;
clean::TypedefItem(ref tydef, _) => {
let id = cx.derive_id(format!("{}.{}", ItemType::AssociatedType, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
clean::AssociatedConstItem(ref ty, ref default) => {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
let src = if let Some(l) = (Item { cx, item }).src_href() {
clean::AssociatedTypeItem(ref bounds, ref default) => {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
- write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+ write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
// We need the stability of the item from the trait
// because impls can't have a stability.
- document_stability(w, cx, it)?;
+ document_stability(w, cx, it, is_hidden)?;
if item.doc_value().is_some() {
- document_full(w, item, cx, "")?;
+ document_full(w, item, cx, "", is_hidden)?;
} else if show_def_docs {
// In case the item isn't documented,
// provide short documentation from the trait.
- document_short(w, cx, it, link, "")?;
+ document_short(w, cx, it, link, "", is_hidden)?;
}
}
} else {
- document_stability(w, cx, item)?;
+ document_stability(w, cx, item, is_hidden)?;
if show_def_docs {
- document_full(w, item, cx, "")?;
+ document_full(w, item, cx, "", is_hidden)?;
}
}
} else {
- document_stability(w, cx, item)?;
+ document_stability(w, cx, item, is_hidden)?;
if show_def_docs {
- document_short(w, cx, item, link, "")?;
+ document_short(w, cx, item, link, "", is_hidden)?;
}
}
}
onEach(document.getElementsByClassName('method'), func);
onEach(document.getElementsByClassName('associatedconstant'), func);
onEach(document.getElementsByClassName('impl'), func);
+ onEach(document.getElementsByClassName('impl-items'), function(e) {
+ onEach(e.getElementsByClassName('associatedconstant'), func);
+ var hiddenElems = e.getElementsByClassName('hidden');
+ var needToggle = false;
+
+ for (var i = 0; i < hiddenElems.length; ++i) {
+ if (hasClass(hiddenElems[i], "content") === false &&
+ hasClass(hiddenElems[i], "docblock") === false) {
+ needToggle = true;
+ break;
+ }
+ }
+ if (needToggle === true) {
+ var newToggle = document.createElement('a');
+ newToggle.href = 'javascript:void(0)';
+ newToggle.className = 'collapse-toggle hidden-default collapsed';
+ newToggle.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) + "</span>" +
+ "] Show hidden undocumented items";
+ newToggle.onclick = function() {
+ if (hasClass(this, "collapsed")) {
+ removeClass(this, "collapsed");
+ onEach(this.parentNode.getElementsByClassName("hidden"), function(x) {
+ if (hasClass(x, "content") === false) {
+ removeClass(x, "hidden");
+ addClass(x, "x");
+ }
+ }, true);
+ this.innerHTML = "[<span class='inner'>" + labelForToggleButton(false) +
+ "</span>] Hide undocumented items"
+ } else {
+ addClass(this, "collapsed");
+ onEach(this.parentNode.getElementsByClassName("x"), function(x) {
+ if (hasClass(x, "content") === false) {
+ addClass(x, "hidden");
+ removeClass(x, "x");
+ }
+ }, true);
+ this.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) +
+ "</span>] Show hidden undocumented items";
+ }
+ };
+ e.insertBefore(newToggle, e.firstChild);
+ }
+ });
function createToggle(otherMessage, fontSize, extraClass, show) {
var span = document.createElement('span');
margin-bottom: 15px;
}
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
- margin-left: 20px;
-}
-.content .impl-items .docblock, .content .impl-items .stability {
- margin-bottom: .6em;
-}
-
-.content .impl-items > .stability {
- margin-left: 40px;
-}
-
.content .docblock > .impl-items {
margin-left: 20px;
margin-top: -34px;
top: -9px;
left: -13px;
}
-.methods > .stability {
+
+.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+ margin-left: 20px;
+}
+
+.content .impl-items .docblock, .content .impl-items .stability {
+ margin-bottom: .6em;
+}
+
+.content .impl-items > .stability {
+ margin-left: 40px;
+}
+
+.methods > .stability, .content .impl-items > .stability {
margin-top: -8px;
}
text-align: center;
}
+.collapse-toggle.hidden-default {
+ position: relative;
+ margin-left: 20px;
+}
+
.ghost {
display: none;
}
var savedHref = [];
-function onEach(arr, func) {
+function onEach(arr, func, reversed) {
if (arr && arr.length > 0 && func) {
- for (var i = 0; i < arr.length; i++) {
- if (func(arr[i]) === true) {
- return true;
+ if (reversed !== true) {
+ for (var i = 0; i < arr.length; ++i) {
+ if (func(arr[i]) === true) {
+ return true;
+ }
+ }
+ } else {
+ for (var i = arr.length - 1; i >= 0; --i) {
+ if (func(arr[i]) === true) {
+ return true;
+ }
}
}
}
dont_insert_main: bool,
opts: &TestOptions)
-> (String, usize) {
- let (crate_attrs, everything_else) = partition_source(s);
+ let (crate_attrs, everything_else, crates) = partition_source(s);
let everything_else = everything_else.trim();
let mut line_offset = 0;
let mut prog = String::new();
// are intended to be crate attributes.
prog.push_str(&crate_attrs);
+ // Uses libsyntax to parse the doctest and find if there's a main fn and the extern
+ // crate already is included.
+ let (already_has_main, already_has_extern_crate) = crate::syntax::with_globals(|| {
+ use crate::syntax::{ast, parse::{self, ParseSess}, source_map::FilePathMapping};
+ use crate::syntax_pos::FileName;
+ use errors::emitter::EmitterWriter;
+ use errors::Handler;
+
+ let filename = FileName::Anon;
+ let source = crates + &everything_else;
+
+ // any errors in parsing should also appear when the doctest is compiled for real, so just
+ // send all the errors that libsyntax emits directly into a Sink instead of stderr
+ let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+ let emitter = EmitterWriter::new(box io::sink(), None, false, false);
+ let handler = Handler::with_emitter(false, false, box emitter);
+ let sess = ParseSess::with_span_handler(handler, cm);
+
+ debug!("about to parse: \n{}", source);
+
+ let mut found_main = false;
+ let mut found_extern_crate = cratename.is_none();
+
+ let mut parser = match parse::maybe_new_parser_from_source_str(&sess, filename, source) {
+ Ok(p) => p,
+ Err(errs) => {
+ for mut err in errs {
+ err.cancel();
+ }
+
+ return (found_main, found_extern_crate);
+ }
+ };
+
+ loop {
+ match parser.parse_item() {
+ Ok(Some(item)) => {
+ if !found_main {
+ if let ast::ItemKind::Fn(..) = item.node {
+ if item.ident.as_str() == "main" {
+ found_main = true;
+ }
+ }
+ }
+
+ if !found_extern_crate {
+ if let ast::ItemKind::ExternCrate(original) = item.node {
+ // This code will never be reached if `cratename` is none because
+ // `found_extern_crate` is initialized to `true` if it is none.
+ let cratename = cratename.unwrap();
+
+ match original {
+ Some(name) => found_extern_crate = name.as_str() == cratename,
+ None => found_extern_crate = item.ident.as_str() == cratename,
+ }
+ }
+ }
+
+ if found_main && found_extern_crate {
+ break;
+ }
+ }
+ Ok(None) => break,
+ Err(mut e) => {
+ e.cancel();
+ break;
+ }
+ }
+ }
+
+ (found_main, found_extern_crate)
+ });
+
// Don't inject `extern crate std` because it's already injected by the
// compiler.
- if !s.contains("extern crate") && !opts.no_crate_inject && cratename != Some("std") {
+ if !already_has_extern_crate && !opts.no_crate_inject && cratename != Some("std") {
if let Some(cratename) = cratename {
+ // Make sure its actually used if not included.
if s.contains(cratename) {
prog.push_str(&format!("extern crate {};\n", cratename));
line_offset += 1;
}
}
- // FIXME (#21299): prefer libsyntax or some other actual parser over this
- // best-effort ad hoc approach
- let already_has_main = s.lines()
- .map(|line| {
- let comment = line.find("//");
- if let Some(comment_begins) = comment {
- &line[0..comment_begins]
- } else {
- line
- }
- })
- .any(|code| code.contains("fn main"));
-
if dont_insert_main || already_has_main {
prog.push_str(everything_else);
} else {
}
// FIXME(aburka): use a real parser to deal with multiline attributes
-fn partition_source(s: &str) -> (String, String) {
+fn partition_source(s: &str) -> (String, String, String) {
let mut after_header = false;
let mut before = String::new();
+ let mut crates = String::new();
let mut after = String::new();
for line in s.lines() {
after.push_str(line);
after.push_str("\n");
} else {
+ if trimline.starts_with("#[macro_use] extern crate")
+ || trimline.starts_with("extern crate") {
+ crates.push_str(line);
+ crates.push_str("\n");
+ }
before.push_str(line);
before.push_str("\n");
}
}
- (before, after)
+ (before, after, crates)
}
pub trait Tester {
let output = make_test(input, None, false, &opts);
assert_eq!(output, (expected, 1));
}
+
+ #[test]
+ fn make_test_issues_21299_33731() {
+ let opts = TestOptions::default();
+
+ let input =
+"// fn main
+assert_eq!(2+2, 4);";
+
+ let expected =
+"#![allow(unused)]
+fn main() {
+// fn main
+assert_eq!(2+2, 4);
+}".to_string();
+
+ let output = make_test(input, None, false, &opts);
+ assert_eq!(output, (expected, 2));
+
+ let input =
+"extern crate hella_qwop;
+assert_eq!(asdf::foo, 4);";
+
+ let expected =
+"#![allow(unused)]
+extern crate hella_qwop;
+extern crate asdf;
+fn main() {
+assert_eq!(asdf::foo, 4);
+}".to_string();
+
+ let output = make_test(input, Some("asdf"), false, &opts);
+ assert_eq!(output, (expected, 3));
+ }
}
}
/// The AST represents all type param bounds as types.
-/// typeck::collect::compute_bounds matches these against
-/// the "special" built-in traits (see middle::lang_items) and
-/// detects Copy, Send and Sync.
+/// `typeck::collect::compute_bounds` matches these against
+/// the "special" built-in traits (see `middle::lang_items`) and
+/// detects `Copy`, `Send` and `Sync`.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum GenericBound {
Trait(PolyTraitRef, TraitBoundModifier),
pub struct MacroExpander<'a, 'b:'a> {
pub cx: &'a mut ExtCtxt<'b>,
- monotonic: bool, // c.f. `cx.monotonic_expander()`
+ monotonic: bool, // cf. `cx.monotonic_expander()`
}
impl<'a, 'b> MacroExpander<'a, 'b> {
if name == "packed" {
gate_feature_post!(&self, repr_packed, attr.span,
"the `#[repr(packed(n))]` attribute \
- is experimental");
+ is experimental");
}
}
}
}
}
- ast::ItemKind::TraitAlias(..) => {
- gate_feature_post!(&self, trait_alias,
- i.span,
- "trait aliases are not yet fully implemented");
- }
-
ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
if polarity == ast::ImplPolarity::Negative {
gate_feature_post!(&self, optin_builtin_traits,
"auto traits are experimental and possibly buggy");
}
+ ast::ItemKind::TraitAlias(..) => {
+ gate_feature_post!(
+ &self,
+ trait_alias,
+ i.span,
+ "trait aliases are experimental"
+ );
+ }
+
ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
let msg = "`macro` is experimental";
gate_feature_post!(&self, decl_macro, i.span, msg);
})
}
+// A variant of 'panictry!' that works on a Vec<Diagnostic> instead of a single DiagnosticBuilder.
+macro_rules! panictry_buffer {
+ ($handler:expr, $e:expr) => ({
+ use std::result::Result::{Ok, Err};
+ use errors::{FatalError, DiagnosticBuilder};
+ match $e {
+ Ok(e) => e,
+ Err(errs) => {
+ for e in errs {
+ DiagnosticBuilder::new_diagnostic($handler, e).emit();
+ }
+ FatalError.raise()
+ }
+ }
+ })
+}
+
#[macro_export]
macro_rules! unwrap_or {
($opt:expr, $default:expr) => {
use ast::{self, Ident};
use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
use source_map::{SourceMap, FilePathMapping};
-use errors::{Applicability, FatalError, DiagnosticBuilder};
+use errors::{Applicability, FatalError, Diagnostic, DiagnosticBuilder};
use parse::{token, ParseSess};
use str::char_at;
use symbol::{Symbol, keywords};
self.fatal_errs.clear();
}
+ pub fn buffer_fatal_errors(&mut self) -> Vec<Diagnostic> {
+ let mut buffer = Vec::new();
+
+ for err in self.fatal_errs.drain(..) {
+ err.buffer(&mut buffer);
+ }
+
+ buffer
+ }
+
pub fn peek(&self) -> TokenAndSpan {
// FIXME(pcwalton): Bad copy!
TokenAndSpan {
Ok(sr)
}
+ pub fn new_or_buffered_errs(sess: &'a ParseSess,
+ source_file: Lrc<syntax_pos::SourceFile>,
+ override_span: Option<Span>) -> Result<Self, Vec<Diagnostic>> {
+ let mut sr = StringReader::new_raw(sess, source_file, override_span);
+ if sr.advance_token().is_err() {
+ Err(sr.buffer_fatal_errors())
+ } else {
+ Ok(sr)
+ }
+ }
+
pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
let begin = sess.source_map().lookup_byte_offset(span.lo());
let end = sess.source_map().lookup_byte_offset(span.hi());
use early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
use source_map::{SourceMap, FilePathMapping};
use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
-use errors::{Handler, ColorConfig, DiagnosticBuilder};
+use errors::{Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
use feature_gate::UnstableFeatures;
use parse::parser::Parser;
use ptr::P;
source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span)
}
-// Create a new parser from a source string
+/// Create a new parser from a source string
pub fn new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String)
-> Parser {
- let mut parser = source_file_to_parser(sess, sess.source_map().new_source_file(name, source));
+ panictry_buffer!(&sess.span_diagnostic, maybe_new_parser_from_source_str(sess, name, source))
+}
+
+/// Create a new parser from a source string. Returns any buffered errors from lexing the initial
+/// token stream.
+pub fn maybe_new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String)
+ -> Result<Parser, Vec<Diagnostic>>
+{
+ let mut parser = maybe_source_file_to_parser(sess,
+ sess.source_map().new_source_file(name, source))?;
parser.recurse_into_file_modules = false;
- parser
+ Ok(parser)
}
/// Create a new parser, handling errors as appropriate
/// Given a source_file and config, return a parser
fn source_file_to_parser(sess: & ParseSess, source_file: Lrc<SourceFile>) -> Parser {
+ panictry_buffer!(&sess.span_diagnostic,
+ maybe_source_file_to_parser(sess, source_file))
+}
+
+/// Given a source_file and config, return a parser. Returns any buffered errors from lexing the
+/// initial token stream.
+fn maybe_source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>)
+ -> Result<Parser, Vec<Diagnostic>>
+{
let end_pos = source_file.end_pos;
- let mut parser = stream_to_parser(sess, source_file_to_stream(sess, source_file, None));
+ let mut parser = stream_to_parser(sess, maybe_file_to_stream(sess, source_file, None)?);
if parser.token == token::Eof && parser.span.is_dummy() {
parser.span = Span::new(end_pos, end_pos, parser.span.ctxt());
}
- parser
+ Ok(parser)
}
// must preserve old name for now, because quote! from the *existing*
pub fn source_file_to_stream(sess: &ParseSess,
source_file: Lrc<SourceFile>,
override_span: Option<Span>) -> TokenStream {
- let mut srdr = lexer::StringReader::new(sess, source_file, override_span);
+ panictry_buffer!(&sess.span_diagnostic, maybe_file_to_stream(sess, source_file, override_span))
+}
+
+/// Given a source file, produce a sequence of token-trees. Returns any buffered errors from
+/// parsing the token tream.
+pub fn maybe_file_to_stream(sess: &ParseSess,
+ source_file: Lrc<SourceFile>,
+ override_span: Option<Span>) -> Result<TokenStream, Vec<Diagnostic>> {
+ let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
srdr.real_token();
- panictry!(srdr.parse_all_token_trees())
+
+ match srdr.parse_all_token_trees() {
+ Ok(stream) => Ok(stream),
+ Err(err) => {
+ let mut buffer = Vec::with_capacity(1);
+ err.buffer(&mut buffer);
+ Err(buffer)
+ }
+ }
}
/// Given stream and the `ParseSess`, produce a parser
t if t.is_special_ident() => "reserved identifier",
t if t.is_used_keyword() => "keyword",
t if t.is_unused_keyword() => "reserved keyword",
+ token::DocComment(..) => "doc comment",
_ => return None,
})
}
Ok(())
} else {
let token_str = pprust::token_to_string(t);
- let this_token_str = self.this_token_to_string();
- let mut err = self.fatal(&format!("expected `{}`, found `{}`",
+ let this_token_str = self.this_token_descr();
+ let mut err = self.fatal(&format!("expected `{}`, found {}",
token_str,
this_token_str));
self.check_keyword(keywords::Extern) && self.is_extern_non_path()
}
- /// parse a TyKind::BareFn type:
+ /// parse a `TyKind::BareFn` type:
fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> {
/*
Some(body)
}
_ => {
- let token_str = self.this_token_to_string();
- let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
+ let token_str = self.this_token_descr();
+ let mut err = self.fatal(&format!("expected `;` or `{{`, found {}",
token_str));
err.span_label(self.span, "expected `;` or `{`");
return Err(err);
}
}
_ => {
- let token_str = self.this_token_to_string();
- let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
+ let token_str = self.this_token_descr();
+ let mut err = self.fatal(&format!("expected `;` or `{{`, found {}",
token_str));
err.span_label(self.span, "expected `;` or `{`");
return Err(err);
if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
let path = match bounds[0] {
GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(),
- _ => self.bug("unexpected lifetime bound"),
+ GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"),
};
self.parse_remaining_bounds(Vec::new(), path, lo, true)?
}
etc_span = Some(etc_sp);
break;
}
- let token_str = self.this_token_to_string();
- let mut err = self.fatal(&format!("expected `}}`, found `{}`", token_str));
+ let token_str = self.this_token_descr();
+ let mut err = self.fatal(&format!("expected `}}`, found {}", token_str));
err.span_label(self.span, "expected `}`");
let mut comma_sp = None;
} else {
""
};
- let tok_str = self.this_token_to_string();
- let mut err = self.fatal(&format!("expected {}`(` or `{{`, found `{}`",
+ let tok_str = self.this_token_descr();
+ let mut err = self.fatal(&format!("expected {}`(` or `{{`, found {}",
ident_str,
tok_str));
err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str));
if !self.eat(&token::OpenDelim(token::Brace)) {
let sp = self.span;
- let tok = self.this_token_to_string();
- let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok));
+ let tok = self.this_token_descr();
+ let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok));
let do_not_suggest_help =
self.token.is_keyword(keywords::In) || self.token == token::Colon;
}
_ => ()
}
+ e.span_label(sp, "expected `{`");
return Err(e);
}
fn warn_missing_semicolon(&self) {
self.diagnostic().struct_span_warn(self.span, {
- &format!("expected `;`, found `{}`", self.this_token_to_string())
+ &format!("expected `;`, found {}", self.this_token_descr())
}).note({
"This was erroneously allowed and will become a hard error in a future release"
}).emit();
ast::ImplItemKind)> {
// code copied from parse_macro_use_or_failure... abstraction!
if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
- // Method macro.
+ // method macro
Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
ast::ImplItemKind::Macro(mac)))
} else {
self.expect(&token::Semi)?;
body
} else {
- let token_str = self.this_token_to_string();
+ let token_str = self.this_token_descr();
let mut err = self.fatal(&format!(
- "expected `where`, `{{`, `(`, or `;` after struct name, found `{}`",
+ "expected `where`, `{{`, `(`, or `;` after struct name, found {}",
token_str
));
err.span_label(self.span, "expected `where`, `{`, `(`, or `;` after struct name");
} else if self.token == token::OpenDelim(token::Brace) {
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
} else {
- let token_str = self.this_token_to_string();
+ let token_str = self.this_token_descr();
let mut err = self.fatal(&format!(
- "expected `where` or `{{` after union name, found `{}`", token_str));
+ "expected `where` or `{{` after union name, found {}", token_str));
err.span_label(self.span, "expected `where` or `{` after union name");
return Err(err);
};
}
self.eat(&token::CloseDelim(token::Brace));
} else {
- let token_str = self.this_token_to_string();
+ let token_str = self.this_token_descr();
let mut err = self.fatal(&format!(
- "expected `where`, or `{{` after struct name, found `{}`", token_str));
+ "expected `where`, or `{{` after struct name, found {}", token_str));
err.span_label(self.span, "expected `where`, or `{` after struct name");
return Err(err);
}
}
_ => {
let sp = self.sess.source_map().next_point(self.prev_span);
- let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found `{}`",
- self.this_token_to_string()));
+ let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found {}",
+ self.this_token_descr()));
if self.token.is_ident() {
// This is likely another field; emit the diagnostic and keep going
err.span_suggestion_with_applicability(
}
if !self.eat(term) {
- let token_str = self.this_token_to_string();
- let mut err = self.fatal(&format!("expected item, found `{}`", token_str));
- if token_str == ";" {
+ let token_str = self.this_token_descr();
+ let mut err = self.fatal(&format!("expected item, found {}", token_str));
+ if self.token == token::Semi {
let msg = "consider removing this semicolon";
err.span_suggestion_short_with_applicability(
self.span, msg, String::new(), Applicability::MachineApplicable
Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs))
}
- /// Parse type Foo = Bar;
+ /// Parse `type Foo = Bar;`
/// or
- /// existential type Foo: Bar;
+ /// `existential type Foo: Bar;`
/// or
- /// return None without modifying the parser state
+ /// `return None` without modifying the parser state
fn eat_type(&mut self) -> Option<PResult<'a, (Ident, AliasKind, ast::Generics)>> {
// This parses the grammar:
// Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";"
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+use std::marker::PhantomData;
+
+trait Empty {}
+trait EmptyAlias = Empty;
+trait CloneDefault = Clone + Default;
+trait SendSyncAlias = Send + Sync;
+trait WhereSendAlias = where Self: Send;
+trait SendEqAlias<T> = Send where T: PartialEq<Self>;
+trait I32Iterator = Iterator<Item = i32>;
+
+#[allow(dead_code)]
+struct Foo<T: SendSyncAlias>(PhantomData<T>);
+#[allow(dead_code)]
+struct Bar<T>(PhantomData<T>) where T: SendSyncAlias;
+
+impl EmptyAlias {}
+
+impl<T: SendSyncAlias> Empty for T {}
+
+fn a<T: CloneDefault>() -> (T, T) {
+ let one = T::default();
+ let two = one.clone();
+ (one, two)
+}
+
+fn b(x: &impl SendEqAlias<i32>) -> bool {
+ 22_i32 == *x
+}
+
+fn c<T: I32Iterator>(x: &mut T) -> Option<i32> {
+ x.next()
+}
+
+fn d<T: SendSyncAlias>() {
+ is_send_and_sync::<T>();
+}
+
+fn is_send_and_sync<T: Send + Sync>() {}
+
+fn main() {
+ let both = a::<i32>();
+ assert_eq!(both.0, 0);
+ assert_eq!(both.1, 0);
+ let both: (i32, i32) = a();
+ assert_eq!(both.0, 0);
+ assert_eq!(both.1, 0);
+
+ assert!(b(&22));
+
+ assert_eq!(c(&mut vec![22].into_iter()), Some(22));
+
+ d::<i32>();
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait Foo = PartialEq<i32> + Send;
+trait Bar = Foo + Sync;
+
+trait I32Iterator = Iterator<Item = i32>;
+
+pub fn main() {
+ let a: &dyn Bar = &123;
+ assert!(*a == 123);
+ let b = Box::new(456) as Box<dyn Foo>;
+ assert!(*b == 456);
+
+ // FIXME(alexreg): associated type should be gotten from trait alias definition
+ // let c: &dyn I32Iterator = &vec![123].into_iter();
+ // assert_eq!(c.next(), Some(123));
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait SimpleAlias = Default;
+trait GenericAlias<T> = Iterator<Item = T>;
+trait Partial<T> = IntoIterator<Item = T>;
+trait SpecificAlias = GenericAlias<i32>;
+trait PartialEqRef<'a, T: 'a> = PartialEq<&'a T>;
+trait StaticAlias = 'static;
+
+trait Things<T> {}
+trait Romeo {}
+#[allow(dead_code)]
+struct The<T>(T);
+#[allow(dead_code)]
+struct Fore<T>(T);
+impl<T, U> Things<T> for The<U> {}
+impl<T> Romeo for Fore<T> {}
+
+trait WithWhere<Art, Thou> = Romeo + Romeo where Fore<(Art, Thou)>: Romeo;
+trait BareWhere<Wild, Are> = where The<Wild>: Things<Are>;
+
+fn main() {}
/// Docs for QUX1 in trait.
const QUX1: i8;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
- // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
- /// Docs for QUX_DEFAULT0 in trait.
+ // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+ /// Docs for QUX_DEFAULT12 in trait.
const QUX_DEFAULT0: u16 = 1;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
// @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in trait."
/// Docs for QUX1 in impl.
const QUX1: i8 = 5;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
- // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
+ // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT12 in trait."
const QUX_DEFAULT0: u16 = 6;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
// @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
--- /dev/null
+// Copyright (c) 2015 Anders Kaseorg <andersk@mit.edu>
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// “Software”), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+//! This crate exports a macro `enum_from_primitive!` that wraps an
+//! `enum` declaration and automatically adds an implementation of
+//! `num::FromPrimitive` (reexported here), to allow conversion from
+//! primitive integers to the enum. It therefore provides an
+//! alternative to the built-in `#[derive(FromPrimitive)]`, which
+//! requires the unstable `std::num::FromPrimitive` and is disabled in
+//! Rust 1.0.
+//!
+//! # Example
+//!
+//! ```
+//! #[macro_use] extern crate enum_primitive;
+//! extern crate num_traits;
+//! use num_traits::FromPrimitive;
+//!
+//! enum_from_primitive! {
+//! #[derive(Debug, PartialEq)]
+//! enum FooBar {
+//! Foo = 17,
+//! Bar = 42,
+//! Baz,
+//! }
+//! }
+//!
+//! fn main() {
+//! assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
+//! assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
+//! assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
+//! assert_eq!(FooBar::from_i32(91), None);
+//! }
+//! ```
+
+
+pub mod num_traits {
+ pub trait FromPrimitive: Sized {
+ fn from_i64(n: i64) -> Option<Self>;
+ fn from_u64(n: u64) -> Option<Self>;
+ }
+}
+
+pub use std::option::Option;
+pub use num_traits::FromPrimitive;
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+macro_rules! enum_from_primitive_impl_ty {
+ ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => {
+ #[allow(non_upper_case_globals, unused)]
+ fn $meth(n: $ty) -> $crate::Option<Self> {
+ $( if n == $name::$variant as $ty {
+ $crate::Option::Some($name::$variant)
+ } else )* {
+ $crate::Option::None
+ }
+ }
+ };
+}
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl_ty)]
+macro_rules! enum_from_primitive_impl {
+ ($name:ident, $( $variant:ident )*) => {
+ impl $crate::FromPrimitive for $name {
+ enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* }
+ enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* }
+ }
+ };
+}
+
+/// Wrap this macro around an `enum` declaration to get an
+/// automatically generated implementation of `num::FromPrimitive`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl)]
+macro_rules! enum_from_primitive {
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( #[$variant_attr:meta] )* $variant:ident ),+
+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( #[$variant_attr] )* $variant ),+
+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+ }
+ enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+ };
+
+ (
+ $( #[$enum_attr:meta] )*
+ pub enum $name:ident {
+ $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+ }
+ ) => {
+ $( #[$enum_attr] )*
+ pub enum $name {
+ $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+ }
+ enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+ };
+}
+
// @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
// @has - '//*[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait a_method definition.'
pub struct S3(usize);
/// Docs associated with the S3 trait implementation.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ensure this code doesn't stack overflow
+// aux-build:enum_primitive.rs
+
+#[macro_use] extern crate enum_primitive;
+
+enum_from_primitive! {
+ pub enum Test {
+ A1,A2,A3,A4,A5,A6,
+ B1,B2,B3,B4,B5,B6,
+ C1,C2,C3,C4,C5,C6,
+ D1,D2,D3,D4,D5,D6,
+ E1,E2,E3,E4,E5,E6,
+ F1,F2,F3,F4,F5,F6,
+ G1,G2,G3,G4,G5,G6,
+ H1,H2,H3,H4,H5,H6,
+ I1,I2,I3,I4,I5,I6,
+ J1,J2,J3,J4,J5,J6,
+ K1,K2,K3,K4,K5,K6,
+ L1,L2,L3,L4,L5,L6,
+ M1,M2,M3,M4,M5,M6,
+ N1,N2,N3,N4,N5,N6,
+ O1,O2,O3,O4,O5,O6,
+ P1,P2,P3,P4,P5,P6,
+ Q1,Q2,Q3,Q4,Q5,Q6,
+ R1,R2,R3,R4,R5,R6,
+ S1,S2,S3,S4,S5,S6,
+ T1,T2,T3,T4,T5,T6,
+ U1,U2,U3,U4,U5,U6,
+ V1,V2,V3,V4,V5,V6,
+ W1,W2,W3,W4,W5,W6,
+ X1,X2,X3,X4,X5,X6,
+ Y1,Y2,Y3,Y4,Y5,Y6,
+ Z1,Z2,Z3,Z4,Z5,Z6,
+ }
+}
+
--> $DIR/two_files.rs:15:6
|
LL | impl Bar for Baz { } //~ ERROR expected trait, found type alias
- | ^^^ type aliases cannot be used for traits
+ | ^^^ type aliases cannot be used as traits
+ |
+ = note: did you mean to use a trait alias?
error: aborting due to previous error
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// compile-flags: -Wunused
+
+// ensure there are no special warnings about uninhabited types
+// when deriving Debug on an empty enum
+
+#[derive(Debug)]
+enum Void {} //~ WARN never used
+
+#[derive(Debug)]
+enum Foo { //~ WARN never used
+ Bar(u8),
+ Void(Void),
+}
+
+fn main() {}
+
--- /dev/null
+warning: enum is never used: `Void`
+ --> $DIR/derive-uninhabited-enum-38885.rs:18:1
+ |
+LL | enum Void {} //~ WARN never used
+ | ^^^^^^^^^
+ |
+ = note: `-W dead-code` implied by `-W unused`
+
+warning: enum is never used: `Foo`
+ --> $DIR/derive-uninhabited-enum-38885.rs:21:1
+ |
+LL | enum Foo { //~ WARN never used
+ | ^^^^^^^^
+
LL | if not // lack of braces is [sic]
| -- this `if` statement has a condition, but no block
LL | println!("Then when?");
- | ^
+ | ^ expected `{`
error: unexpected `2` after identifier
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:36:24
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo = Default;
+
+fn main() {}
--- /dev/null
+error[E0658]: trait aliases are experimental (see issue #41517)
+ --> $DIR/feature-gate-trait-alias.rs:11:1
+ |
+LL | trait Foo = Default;
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(trait_alias)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
}
}
//~^ ERROR expected `{`, found `}`
+//~| NOTE expected `{`
| -- this `if` statement has a condition, but no block
...
LL | }
- | ^
+ | ^ expected `{`
error: aborting due to previous error
-error: expected `{`, found `in`
+error: expected `{`, found keyword `in`
--> $DIR/issue-51602.rs:12:10
|
LL | if i in 1..10 {
| this `if` statement has a condition, but no block
...
LL | get_opt!(bar, foo);
- | ^^^
+ | ^^^ expected `{`
error: aborting due to previous error
LL | if true 'b: {} //~ ERROR expected `{`, found `'b`
| -- ^^----
| | |
+ | | expected `{`
| | help: try placing this code inside a block: `{ 'b: { } }`
| this `if` statement has a condition, but no block
LL | if true {} else 'b: {} //~ ERROR expected `{`, found `'b`
| ^^----
| |
+ | expected `{`
| help: try placing this code inside a block: `{ 'b: { } }`
error: expected one of `.`, `?`, `{`, or an operator, found `'b`
--> $DIR/missing-block-hint.rs:13:18
|
LL | if (foo) => {} //~ ERROR expected `{`, found `=>`
- | -- ^^
+ | -- ^^ expected `{`
| |
| this `if` statement has a condition, but no block
LL | bar; //~ ERROR expected `{`, found `bar`
| ^^^-
| |
+ | expected `{`
| help: try placing this code inside a block: `{ bar; }`
error: aborting due to 2 previous errors
-warning: expected `;`, found `let`
+warning: expected `;`, found keyword `let`
--> $DIR/missing-semicolon-warning.rs:16:12
|
LL | $( let x = $e1 )*; //~ WARN expected `;`
fn /// document
foo() {}
-//~^^ ERROR expected identifier, found `/// document`
+//~^^ ERROR expected identifier, found doc comment `/// document`
fn main() {
foo();
-error: expected identifier, found `/// document`
+error: expected identifier, found doc comment `/// document`
--> $DIR/doc-before-identifier.rs:13:4
|
LL | fn /// document
- | ^^^^^^^^^^^^ expected identifier
+ | ^^^^^^^^^^^^ expected identifier, found doc comment
error: aborting due to previous error
--- /dev/null
+fn main() {
+ if true /*!*/ {}
+ //~^ ERROR expected `{`, found doc comment `/*!*/`
+}
--- /dev/null
+error: expected `{`, found doc comment `/*!*/`
+ --> $DIR/doc-comment-in-if-statement.rs:2:13
+ |
+LL | if true /*!*/ {}
+ | -- ^^^^^ expected `{`
+ | |
+ | this `if` statement has a condition, but no block
+
+error: aborting due to previous error
+
-error: expected `;`, found `as`
+error: expected `;`, found keyword `as`
--> $DIR/import-from-rename.rs:15:16
|
LL | use foo::{bar} as baz;
-error: expected `;`, found `as`
+error: expected `;`, found keyword `as`
--> $DIR/import-glob-rename.rs:15:12
|
LL | use foo::* as baz;
// compile-flags: -Z parse-only -Z continue-parse-after-error
-struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found `where`
+struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found keyword `where`
fn main() {}
-error: expected item, found `where`
+error: expected item, found keyword `where`
--> $DIR/issue-17904-2.rs:13:24
|
-LL | struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found `where`
+LL | struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found keyword `where`
| ^^^^^ expected item
error: aborting due to previous error
// Test syntax checks for `type` keyword.
-struct S1 for type; //~ ERROR expected `where`, `{`, `(`, or `;` after struct name, found `for`
+struct S1 for type;
+//~^ ERROR expected `where`, `{`, `(`, or `;` after struct name, found keyword `for`
pub fn main() {
}
-error: expected `where`, `{`, `(`, or `;` after struct name, found `for`
+error: expected `where`, `{`, `(`, or `;` after struct name, found keyword `for`
--> $DIR/unsized.rs:15:11
|
-LL | struct S1 for type; //~ ERROR expected `where`, `{`, `(`, or `;` after struct name, found `for`
+LL | struct S1 for type;
| ^^^ expected `where`, `{`, `(`, or `;` after struct name
error: aborting due to previous error
// Test diagnostics for the removed struct inheritance feature.
-virtual struct SuperStruct { //~ ERROR expected item, found `virtual`
+virtual struct SuperStruct {
+//~^ ERROR expected item, found reserved keyword `virtual`
f1: isize,
}
-error: expected item, found `virtual`
+error: expected item, found reserved keyword `virtual`
--> $DIR/virtual-structs.rs:15:1
|
-LL | virtual struct SuperStruct { //~ ERROR expected item, found `virtual`
+LL | virtual struct SuperStruct {
| ^^^^^^^ expected item
error: aborting due to previous error
--> $DIR/issue-3907.rs:20:6
|
LL | impl Foo for S { //~ ERROR expected trait, found type alias `Foo`
- | ^^^ type aliases cannot be used for traits
+ | ^^^ type aliases cannot be used as traits
+ |
+ = note: did you mean to use a trait alias?
help: possible better candidate is found in another module, you can import it into scope
|
LL | use issue_3907::Foo;
| ^
| |
| did you mean `I`?
- | type aliases cannot be used for traits
+ | type aliases cannot be used as traits
+ |
+ = note: did you mean to use a trait alias?
error: aborting due to 2 previous errors
--> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:16:8
|
LL | fn g<F:Typedef(isize) -> isize>(x: F) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used for traits
+ | ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used as traits
+ |
+ = note: did you mean to use a trait alias?
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+#![feature(in_band_lifetimes)]
+#![deny(single_use_lifetimes)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument, even with in band lifetimes.
+
+fn a(x: &u32, y: &u32) {
+ //~^ ERROR `'a` only used once
+ //~| ERROR `'b` only used once
+ //~| HELP elide the single-use lifetime
+ //~| HELP elide the single-use lifetime
+}
+
+fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// run-rustfix
+
#![feature(in_band_lifetimes)]
#![deny(single_use_lifetimes)]
#![allow(dead_code)]
fn a(x: &'a u32, y: &'b u32) {
//~^ ERROR `'a` only used once
//~| ERROR `'b` only used once
+ //~| HELP elide the single-use lifetime
+ //~| HELP elide the single-use lifetime
}
fn main() { }
error: lifetime parameter `'a` only used once
- --> $DIR/one-use-in-fn-argument-in-band.rs:19:10
+ --> $DIR/one-use-in-fn-argument-in-band.rs:21:10
|
LL | fn a(x: &'a u32, y: &'b u32) {
- | ^^
+ | ^^-
| |
- | this lifetime...
- | ...is used only here
+ | this lifetime is only used here
+ | help: elide the single-use lifetime
|
note: lint level defined here
- --> $DIR/one-use-in-fn-argument-in-band.rs:12:9
+ --> $DIR/one-use-in-fn-argument-in-band.rs:14:9
|
LL | #![deny(single_use_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^
error: lifetime parameter `'b` only used once
- --> $DIR/one-use-in-fn-argument-in-band.rs:19:22
+ --> $DIR/one-use-in-fn-argument-in-band.rs:21:22
|
LL | fn a(x: &'a u32, y: &'b u32) {
- | ^^
+ | ^^-
| |
- | this lifetime...
- | ...is used only here
+ | this lifetime is only used here
+ | help: elide the single-use lifetime
error: aborting due to 2 previous errors
// once in a fn argument.
fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+ //~^ HELP elide the single-use lifetime
}
fn main() { }
|
LL | #![deny(single_use_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^
+help: elide the single-use lifetime
+ |
+LL | fn a(x: &u32) { //~ ERROR `'a` only used once
+ | -- --
error: aborting due to previous error
#![allow(dead_code)]
#![allow(unused_variables)]
-// Test that we DO warn for a lifetime used only once in an impl.
-//
-// (Actually, until #15872 is fixed, you can't use `'_` here, but
-// hopefully that will come soon.)
+// Test that we DO warn for a lifetime used only once in an impl, and that we
+// don't warn for the anonymous lifetime.
struct Foo<'f> {
data: &'f u32
}
}
+impl Foo<'_> {
+ fn inherent_b(&self) {}
+}
+
+
fn main() { }
error: lifetime parameter `'f` only used once
- --> $DIR/one-use-in-inherent-impl-header.rs:24:6
+ --> $DIR/one-use-in-inherent-impl-header.rs:22:6
|
LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
| ^^ -- ...is used only here
impl<'f> Foo<'f> { //~ ERROR `'f` only used once
fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+ //~^ HELP elide the single-use lifetime
}
}
|
LL | #![deny(single_use_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^
+help: elide the single-use lifetime
+ |
+LL | fn inherent_a(&self, data: &u32) { //~ ERROR `'a` only used once
+ | -- --
error: lifetime parameter `'f` only used once
--> $DIR/one-use-in-inherent-method-argument.rs:21:6
type Item = &'f u32;
fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+ //~^ HELP elide the single-use lifetime
None
}
}
|
LL | #![deny(single_use_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^
+help: elide the single-use lifetime
+ |
+LL | fn next(&mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+ | ----
error: aborting due to previous error
fn september() {}
//~^ ERROR lifetime parameter `'a` never used
-//~| HELP remove it
+//~| HELP elide the unused lifetime
fn october<'b, T>(s: &'b T) -> &'b T {
//~^ ERROR lifetime parameter `'a` never used
- //~| HELP remove it
+ //~| HELP elide the unused lifetime
s
}
fn november<'a>(s: &'a str) -> (&'a str) {
//~^ ERROR lifetime parameter `'b` never used
- //~| HELP remove it
+ //~| HELP elide the unused lifetime
s
}
fn september<'a>() {}
//~^ ERROR lifetime parameter `'a` never used
-//~| HELP remove it
+//~| HELP elide the unused lifetime
fn october<'a, 'b, T>(s: &'b T) -> &'b T {
//~^ ERROR lifetime parameter `'a` never used
- //~| HELP remove it
+ //~| HELP elide the unused lifetime
s
}
fn november<'a, 'b>(s: &'a str) -> (&'a str) {
//~^ ERROR lifetime parameter `'b` never used
- //~| HELP remove it
+ //~| HELP elide the unused lifetime
s
}
--> $DIR/zero-uses-in-fn.rs:8:14
|
LL | fn september<'a>() {}
- | -^^- help: remove it
+ | -^^- help: elide the unused lifetime
|
note: lint level defined here
--> $DIR/zero-uses-in-fn.rs:5:9
LL | fn october<'a, 'b, T>(s: &'b T) -> &'b T {
| ^^--
| |
- | help: remove it
+ | help: elide the unused lifetime
error: lifetime parameter `'b` never used
--> $DIR/zero-uses-in-fn.rs:18:17
LL | fn november<'a, 'b>(s: &'a str) -> (&'a str) {
| --^^
| |
- | help: remove it
+ | help: elide the unused lifetime
error: aborting due to 3 previous errors
--> $DIR/zero-uses-in-impl.rs:8:6
|
LL | impl<'a> Foo {} //~ ERROR `'a` never used
- | -^^- help: remove it
+ | -^^- help: elide the unused lifetime
|
note: lint level defined here
--> $DIR/zero-uses-in-impl.rs:3:9
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// gate-test-trait_alias
-
-trait Alias1<T> = Default where T: Clone; // ok
- //~^ERROR trait aliases are not yet fully implemented
-trait Alias2<T: Clone = ()> = Default;
- //~^ERROR type parameters on the left side of a trait alias cannot be bounded
- //~^^ERROR type parameters on the left side of a trait alias cannot have defaults
- //~^^^ERROR trait aliases are not yet fully implemented
-
-impl Alias1 { //~ERROR expected type, found trait alias
-}
-
-impl Alias1 for () { //~ERROR expected trait, found trait alias
-}
-
-fn main() {}
-
+++ /dev/null
-error: type parameters on the left side of a trait alias cannot be bounded
- --> $DIR/trait-alias-fail.rs:15:14
- |
-LL | trait Alias2<T: Clone = ()> = Default;
- | ^
-
-error: type parameters on the left side of a trait alias cannot have defaults
- --> $DIR/trait-alias-fail.rs:15:14
- |
-LL | trait Alias2<T: Clone = ()> = Default;
- | ^
-
-error[E0573]: expected type, found trait alias `Alias1`
- --> $DIR/trait-alias-fail.rs:20:6
- |
-LL | impl Alias1 { //~ERROR expected type, found trait alias
- | ^^^^^^ not a type
-
-error[E0404]: expected trait, found trait alias `Alias1`
- --> $DIR/trait-alias-fail.rs:23:6
- |
-LL | impl Alias1 for () { //~ERROR expected trait, found trait alias
- | ^^^^^^ not a trait
-
-error[E0658]: trait aliases are not yet fully implemented (see issue #41517)
- --> $DIR/trait-alias-fail.rs:13:1
- |
-LL | trait Alias1<T> = Default where T: Clone; // ok
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(trait_alias)] to the crate attributes to enable
-
-error[E0658]: trait aliases are not yet fully implemented (see issue #41517)
- --> $DIR/trait-alias-fail.rs:15:1
- |
-LL | trait Alias2<T: Clone = ()> = Default;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(trait_alias)] to the crate attributes to enable
-
-error: aborting due to 6 previous errors
-
-Some errors occurred: E0404, E0573, E0658.
-For more information about an error, try `rustc --explain E0404`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait DefaultAlias = Default;
+
+impl DefaultAlias for () {}
+
+fn main() {}
--- /dev/null
+error[E0404]: expected trait, found trait alias `DefaultAlias`
+ --> $DIR/trait-alias-impl.rs:15:6
+ |
+LL | impl DefaultAlias for () {}
+ | ^^^^^^^^^^^^ not a trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0404`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait EqAlias = Eq;
+trait IteratorAlias = Iterator;
+
+fn main() {
+ let _: &dyn EqAlias = &123;
+ let _: &dyn IteratorAlias = &vec![123].into_iter();
+}
--- /dev/null
+error[E0038]: the trait `EqAlias` cannot be made into an object
+ --> $DIR/trait-alias-objects.rs:17:13
+ |
+LL | let _: &dyn EqAlias = &123;
+ | ^^^^^^^^^^^ the trait `EqAlias` cannot be made into an object
+ |
+ = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses
+
+error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified
+ --> $DIR/trait-alias-objects.rs:18:13
+ |
+LL | let _: &dyn IteratorAlias = &vec![123].into_iter();
+ | ^^^^^^^^^^^^^^^^^ missing associated type `Item` value
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0038, E0191.
+For more information about an error, try `rustc --explain E0038`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait Foo {}
+trait A<T: Foo> {}
+trait B<T> = A<T>; // T cannot be unbounded
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/trait-alias-wf.rs:15:1
+ |
+LL | trait B<T> = A<T>; // T cannot be unbounded
+ | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+ = help: consider adding a `where T: Foo` bound
+note: required by `A`
+ --> $DIR/trait-alias-wf.rs:14:1
+ |
+LL | trait A<T: Foo> {}
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(trait_alias)]
-
-trait SimpleAlias = Default; //~ERROR E0645
-trait GenericAlias<T> = Iterator<Item=T>; //~ERROR E0645
-trait Partial<T> = IntoIterator<Item=T>; //~ERROR E0645
-
-trait Things<T> {}
-trait Romeo {}
-struct The<T>(T);
-struct Fore<T>(T);
-impl<T, U> Things<T> for The<U> {}
-impl<T> Romeo for Fore<T> {}
-
-trait WithWhere<Art, Thou> = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; //~ERROR E0645
-trait BareWhere<Wild, Are> = where The<Wild>: Things<Are>; //~ERROR E0645
-
-trait CD = Clone + Default; //~ERROR E0645
-
-fn foo<T: CD>() -> (T, T) {
- let one = T::default();
- let two = one.clone();
- (one, two)
-}
-
-fn main() {
- let both = foo();
- assert_eq!(both.0, 0);
- assert_eq!(both.1, 0);
- let both: (i32, i32) = foo();
- assert_eq!(both.0, 0);
- assert_eq!(both.1, 0);
-}
-
+++ /dev/null
-error[E0645]: trait aliases are not yet implemented (see issue #41517)
- --> $DIR/trait-alias.rs:13:1
- |
-LL | trait SimpleAlias = Default; //~ERROR E0645
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0645]: trait aliases are not yet implemented (see issue #41517)
- --> $DIR/trait-alias.rs:14:1
- |
-LL | trait GenericAlias<T> = Iterator<Item=T>; //~ERROR E0645
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0645]: trait aliases are not yet implemented (see issue #41517)
- --> $DIR/trait-alias.rs:15:1
- |
-LL | trait Partial<T> = IntoIterator<Item=T>; //~ERROR E0645
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0645]: trait aliases are not yet implemented (see issue #41517)
- --> $DIR/trait-alias.rs:24:1
- |
-LL | trait WithWhere<Art, Thou> = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; //~ERROR E0645
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0645]: trait aliases are not yet implemented (see issue #41517)
- --> $DIR/trait-alias.rs:25:1
- |
-LL | trait BareWhere<Wild, Are> = where The<Wild>: Things<Are>; //~ERROR E0645
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0645]: trait aliases are not yet implemented (see issue #41517)
- --> $DIR/trait-alias.rs:27:1
- |
-LL | trait CD = Clone + Default; //~ERROR E0645
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0645`.
-Subproject commit a20599ab57d08bb61cd177f9c0c98ec395376dd8
+Subproject commit 71ec4ff636b9315cfaadd30e45338a077ed98a9b
#![feature(rustc_private)]
+extern crate env_logger;
extern crate syntax;
extern crate rustdoc;
extern crate serialize as rustc_serialize;
}
fn main() {
+ env_logger::init();
PLAYGROUND.with(|slot| {
*slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/")));
});
MAINTAINERS = {
'miri': '@oli-obk @RalfJung @eddyb',
'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk',
- 'rls': '@nrc',
+ 'rls': '@nrc @Xanewok',
'rustfmt': '@nrc',
'book': '@carols10cents @steveklabnik',
'nomicon': '@frewsxcv @Gankro',
status[os] = new
if new > old:
changed = True
- message += '🎉 {} on {}: {} → {}.\n' \
- .format(tool, os, old, new)
+ message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \
+ .format(tool, os, old, new, MAINTAINERS.get(tool))
elif new < old:
changed = True
message += '💔 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \