let table = match p.parse() {
Some(table) => table,
None => {
- println!("failed to parse TOML configuration:");
+ println!("failed to parse TOML configuration '{}':", file.to_str().unwrap());
for err in p.errors.iter() {
let (loline, locol) = p.to_linecol(err.lo);
let (hiline, hicol) = p.to_linecol(err.hi);
--- /dev/null
+#!/bin/sh
+# 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.
+
+set -ex
+
+URL=https://dl.google.com/android/repository
+
+download_ndk() {
+ mkdir -p /android/ndk
+ cd /android/ndk
+ curl -O $URL/$1
+ unzip -q $1
+ rm $1
+ mv android-ndk-* ndk
+}
+
+make_standalone_toolchain() {
+ # See https://developer.android.com/ndk/guides/standalone_toolchain.htm
+ python2.7 /android/ndk/ndk/build/tools/make_standalone_toolchain.py \
+ --install-dir /android/ndk/$1-$2 \
+ --arch $1 \
+ --api $2
+}
+
+remove_ndk() {
+ rm -rf /android/ndk/ndk
+}
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ unzip \
+ sudo \
+ xz-utils \
+ libssl-dev \
+ pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+ dpkg -i dumb-init_*.deb && \
+ rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+ download_ndk android-ndk-r13b-linux-x86_64.zip && \
+ make_standalone_toolchain arm64 21 && \
+ remove_ndk
+
+ENV PATH=$PATH:/android/ndk/arm64-21/bin
+
+ENV DEP_Z_ROOT=/android/ndk/arm64-21/sysroot/usr/
+
+ENV HOSTS=aarch64-linux-android
+
+ENV RUST_CONFIGURE_ARGS \
+ --host=$HOSTS \
+ --target=$HOSTS \
+ --aarch64-linux-android-ndk=/android/ndk/arm64-21 \
+ --disable-rpath \
+ --enable-extended \
+ --enable-cargo-openssl-static
+
+ENV SCRIPT python2.7 ../x.py dist --target $HOSTS --host $HOSTS
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ unzip \
+ sudo \
+ xz-utils \
+ libssl-dev \
+ pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+ dpkg -i dumb-init_*.deb && \
+ rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+ download_ndk android-ndk-r13b-linux-x86_64.zip && \
+ make_standalone_toolchain arm 9 && \
+ make_standalone_toolchain arm 21 && \
+ remove_ndk
+
+ENV PATH=$PATH:/android/ndk/arm-9/bin
+
+ENV DEP_Z_ROOT=/android/ndk/arm-9/sysroot/usr/
+
+ENV HOSTS=armv7-linux-androideabi
+
+ENV RUST_CONFIGURE_ARGS \
+ --host=$HOSTS \
+ --target=$HOSTS \
+ --armv7-linux-androideabi-ndk=/android/ndk/arm \
+ --disable-rpath \
+ --enable-extended \
+ --enable-cargo-openssl-static
+
+# We support api level 9, but api level 21 is required to build llvm. To
+# overcome this problem we use a ndk with api level 21 to build llvm and then
+# switch to a ndk with api level 9 to complete the build. When the linker is
+# invoked there are missing symbols (like sigsetempty, not available with api
+# level 9), the default linker behavior is to generate an error, to allow the
+# build to finish we use --warn-unresolved-symbols. Note that the missing
+# symbols does not affect std, only the compiler (llvm) and cargo (openssl).
+RUN chmod 777 /android/ndk && \
+ ln -s /android/ndk/arm-21 /android/ndk/arm
+
+ENV SCRIPT \
+ python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \
+ (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \
+ rm /android/ndk/arm && \
+ ln -s /android/ndk/arm-9 /android/ndk/arm && \
+ python2.7 ../x.py dist --host $HOSTS --target $HOSTS)
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ unzip \
+ sudo \
+ xz-utils \
+ libssl-dev \
+ pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+ dpkg -i dumb-init_*.deb && \
+ rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+ download_ndk android-ndk-r13b-linux-x86_64.zip && \
+ make_standalone_toolchain x86 9 && \
+ make_standalone_toolchain x86 21 && \
+ remove_ndk
+
+ENV PATH=$PATH:/android/ndk/x86-9/bin
+
+ENV DEP_Z_ROOT=/android/ndk/x86-9/sysroot/usr/
+
+ENV HOSTS=i686-linux-android
+
+ENV RUST_CONFIGURE_ARGS \
+ --host=$HOSTS \
+ --target=$HOSTS \
+ --i686-linux-android-ndk=/android/ndk/x86 \
+ --disable-rpath \
+ --enable-extended \
+ --enable-cargo-openssl-static
+
+# We support api level 9, but api level 21 is required to build llvm. To
+# overcome this problem we use a ndk with api level 21 to build llvm and then
+# switch to a ndk with api level 9 to complete the build. When the linker is
+# invoked there are missing symbols (like sigsetempty, not available with api
+# level 9), the default linker behavior is to generate an error, to allow the
+# build to finish we use --warn-unresolved-symbols. Note that the missing
+# symbols does not affect std, only the compiler (llvm) and cargo (openssl).
+RUN chmod 777 /android/ndk && \
+ ln -s /android/ndk/x86-21 /android/ndk/x86
+
+ENV SCRIPT \
+ python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \
+ (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \
+ rm /android/ndk/x86 && \
+ ln -s /android/ndk/x86-9 /android/ndk/x86 && \
+ python2.7 ../x.py dist --host $HOSTS --target $HOSTS)
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ unzip \
+ sudo \
+ xz-utils \
+ libssl-dev \
+ pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+ dpkg -i dumb-init_*.deb && \
+ rm dumb-init_*.deb
+
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+COPY android-ndk.sh /
+RUN . /android-ndk.sh && \
+ download_ndk android-ndk-r13b-linux-x86_64.zip && \
+ make_standalone_toolchain x86_64 21 && \
+ remove_ndk
+
+ENV PATH=$PATH:/android/ndk/x86_64-21/bin
+
+ENV DEP_Z_ROOT=/android/ndk/x86_64-21/sysroot/usr/
+
+ENV HOSTS=x86_64-linux-android
+
+ENV RUST_CONFIGURE_ARGS \
+ --host=$HOSTS \
+ --target=$HOSTS \
+ --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
+ --disable-rpath \
+ --enable-extended \
+ --enable-cargo-openssl-static
+
+ENV SCRIPT python2.7 ../x.py dist --target $HOSTS --host $HOSTS
source "$ci_dir/shared.sh"
-retry docker \
- build \
- --rm \
- -t rust-ci \
- "`dirname "$script"`/$image"
+if [ -f "$docker_dir/$image/Dockerfile" ]; then
+ retry docker \
+ build \
+ --rm \
+ -t rust-ci \
+ "$docker_dir/$image"
+elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
+ if [ -n "$TRAVIS_OS_NAME" ]; then
+ echo Cannot run disabled images on travis!
+ exit 1
+ fi
+ retry docker \
+ build \
+ --rm \
+ -t rust-ci \
+ -f "$docker_dir/disabled/$image/Dockerfile" \
+ "$docker_dir"
+else
+ echo Invalid image: $image
+ exit 1
+fi
objdir=$root_dir/obj
use ty::{IntType, UintType};
use ty::{self, Ty, TyCtxt};
use ty::error::TypeError;
-use ty::fold::TypeFoldable;
-use ty::relate::{RelateResult, TypeRelation};
-use traits::PredicateObligations;
+use ty::relate::{self, Relate, RelateResult, TypeRelation};
+use traits::{Obligation, PredicateObligations};
use syntax::ast;
use syntax_pos::Span;
// `'?2` and `?3` are fresh region/type inference
// variables. (Down below, we will relate `a_ty <: b_ty`,
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
- let b_ty = self.generalize(a_ty, b_vid, dir == EqTo)?;
+ let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
debug!("instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
a_ty, dir, b_vid, b_ty);
self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty);
+ if needs_wf {
+ self.obligations.push(Obligation::new(self.trace.cause.clone(),
+ ty::Predicate::WellFormed(b_ty)));
+ }
+
// Finally, relate `b_ty` to `a_ty`, as described in previous comment.
//
// FIXME(#16847): This code is non-ideal because all these subtype
/// Attempts to generalize `ty` for the type variable `for_vid`.
/// This checks for cycle -- that is, whether the type `ty`
- /// references `for_vid`. If `is_eq_relation` is false, it will
- /// also replace all regions/unbound-type-variables with fresh
- /// variables. Returns `TyError` in the case of a cycle, `Ok`
- /// otherwise.
+ /// references `for_vid`. The `dir` is the "direction" for which we
+ /// a performing the generalization (i.e., are we producing a type
+ /// that can be used as a supertype etc).
///
/// Preconditions:
///
fn generalize(&self,
ty: Ty<'tcx>,
for_vid: ty::TyVid,
- is_eq_relation: bool)
- -> RelateResult<'tcx, Ty<'tcx>>
+ dir: RelationDir)
+ -> RelateResult<'tcx, Generalization<'tcx>>
{
+ // Determine the ambient variance within which `ty` appears.
+ // The surrounding equation is:
+ //
+ // ty [op] ty2
+ //
+ // where `op` is either `==`, `<:`, or `:>`. This maps quite
+ // naturally.
+ let ambient_variance = match dir {
+ RelationDir::EqTo => ty::Invariant,
+ RelationDir::SubtypeOf => ty::Covariant,
+ RelationDir::SupertypeOf => ty::Contravariant,
+ };
+
let mut generalize = Generalizer {
infcx: self.infcx,
span: self.trace.cause.span,
for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid),
- is_eq_relation: is_eq_relation,
- cycle_detected: false
+ ambient_variance: ambient_variance,
+ needs_wf: false,
};
- let u = ty.fold_with(&mut generalize);
- if generalize.cycle_detected {
- Err(TypeError::CyclicTy)
- } else {
- Ok(u)
- }
+
+ let ty = generalize.relate(&ty, &ty)?;
+ let needs_wf = generalize.needs_wf;
+ Ok(Generalization { ty, needs_wf })
}
}
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
span: Span,
for_vid_sub_root: ty::TyVid,
- is_eq_relation: bool,
- cycle_detected: bool,
+ ambient_variance: ty::Variance,
+ needs_wf: bool, // see the field `needs_wf` in `Generalization`
}
-impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx, 'tcx> {
- fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
+/// Result from a generalization operation. This includes
+/// not only the generalized type, but also a bool flag
+/// indicating whether further WF checks are needed.q
+struct Generalization<'tcx> {
+ ty: Ty<'tcx>,
+
+ /// If true, then the generalized type may not be well-formed,
+ /// even if the source type is well-formed, so we should add an
+ /// additional check to enforce that it is. This arises in
+ /// particular around 'bivariant' type parameters that are only
+ /// constrained by a where-clause. As an example, imagine a type:
+ ///
+ /// struct Foo<A, B> where A: Iterator<Item=B> {
+ /// data: A
+ /// }
+ ///
+ /// here, `A` will be covariant, but `B` is
+ /// unconstrained. However, whatever it is, for `Foo` to be WF, it
+ /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
+ /// then after generalization we will wind up with a type like
+ /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
+ /// ?D>` (or `>:`), we will wind up with the requirement that `?A
+ /// <: ?C`, but no particular relationship between `?B` and `?D`
+ /// (after all, we do not know the variance of the normalized form
+ /// of `A::Item` with respect to `A`). If we do nothing else, this
+ /// may mean that `?D` goes unconstrained (as in #41677). So, in
+ /// this scenario where we create a new type variable in a
+ /// bivariant context, we set the `needs_wf` flag to true. This
+ /// will force the calling code to check that `WF(Foo<?C, ?D>)`
+ /// holds, which in turn implies that `?C::Item == ?D`. So once
+ /// `?C` is constrained, that should suffice to restrict `?D`.
+ needs_wf: bool,
+}
+
+impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
self.infcx.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn tag(&self) -> &'static str {
+ "Generalizer"
+ }
+
+ fn a_is_expected(&self) -> bool {
+ true
+ }
+
+ fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
+ -> RelateResult<'tcx, ty::Binder<T>>
+ where T: Relate<'tcx>
+ {
+ Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?))
+ }
+
+ fn relate_with_variance<T: Relate<'tcx>>(&mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T)
+ -> RelateResult<'tcx, T>
+ {
+ let old_ambient_variance = self.ambient_variance;
+ self.ambient_variance = self.ambient_variance.xform(variance);
+
+ let result = self.relate(a, b);
+ self.ambient_variance = old_ambient_variance;
+ result
+ }
+
+ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
+
// Check to see whether the type we are genealizing references
// any other type variable related to `vid` via
// subtyping. This is basically our "occurs check", preventing
if sub_vid == self.for_vid_sub_root {
// If sub-roots are equal, then `for_vid` and
// `vid` are related via subtyping.
- self.cycle_detected = true;
- self.tcx().types.err
+ return Err(TypeError::CyclicTy);
} else {
match variables.probe_root(vid) {
Some(u) => {
drop(variables);
- self.fold_ty(u)
+ self.relate(&u, &u)
}
None => {
- if !self.is_eq_relation {
- let origin = variables.origin(vid);
- let new_var_id = variables.new_var(false, origin, None);
- let u = self.tcx().mk_var(new_var_id);
- debug!("generalize: replacing original vid={:?} with new={:?}",
- vid, u);
- u
- } else {
- t
+ match self.ambient_variance {
+ // Invariant: no need to make a fresh type variable.
+ ty::Invariant => return Ok(t),
+
+ // Bivariant: make a fresh var, but we
+ // may need a WF predicate. See
+ // comment on `needs_wf` field for
+ // more info.
+ ty::Bivariant => self.needs_wf = true,
+
+ // Co/contravariant: this will be
+ // sufficiently constrained later on.
+ ty::Covariant | ty::Contravariant => (),
}
+
+ let origin = variables.origin(vid);
+ let new_var_id = variables.new_var(false, origin, None);
+ let u = self.tcx().mk_var(new_var_id);
+ debug!("generalize: replacing original vid={:?} with new={:?}",
+ vid, u);
+ return Ok(u);
}
}
}
}
+ ty::TyInfer(ty::IntVar(_)) |
+ ty::TyInfer(ty::FloatVar(_)) => {
+ // No matter what mode we are in,
+ // integer/floating-point types must be equal to be
+ // relatable.
+ Ok(t)
+ }
_ => {
- t.super_fold_with(self)
+ relate::super_relate_tys(self, t, t)
}
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn regions(&mut self, r: ty::Region<'tcx>, r2: ty::Region<'tcx>)
+ -> RelateResult<'tcx, ty::Region<'tcx>> {
+ assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
+
match *r {
// Never make variables for regions bound within the type itself,
// nor for erased regions.
ty::ReLateBound(..) |
- ty::ReErased => { return r; }
+ ty::ReErased => {
+ return Ok(r);
+ }
// Early-bound regions should really have been substituted away before
// we get to this point.
ty::ReScope(..) |
ty::ReVar(..) |
ty::ReFree(..) => {
- if self.is_eq_relation {
- return r;
+ match self.ambient_variance {
+ ty::Invariant => return Ok(r),
+ ty::Bivariant | ty::Covariant | ty::Contravariant => (),
}
}
}
// FIXME: This is non-ideal because we don't give a
// very descriptive origin for this region variable.
- self.infcx.next_region_var(MiscVariable(self.span))
+ Ok(self.infcx.next_region_var(MiscVariable(self.span)))
}
}
use super::combine::{CombineFields, RelationDir};
use super::{Subtype};
+use hir::def_id::DefId;
+
use ty::{self, Ty, TyCtxt};
use ty::TyVar;
-use ty::relate::{Relate, RelateResult, TypeRelation};
+use ty::subst::Substs;
+use ty::relate::{self, Relate, RelateResult, TypeRelation};
/// Ensures `a` is made equal to `b`. Returns `a` on success.
pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
fn a_is_expected(&self) -> bool { self.a_is_expected }
+ fn relate_item_substs(&mut self,
+ _item_def_id: DefId,
+ a_subst: &'tcx Substs<'tcx>,
+ b_subst: &'tcx Substs<'tcx>)
+ -> RelateResult<'tcx, &'tcx Substs<'tcx>>
+ {
+ // NB: Once we are equating types, we don't care about
+ // variance, so don't try to lookup the variance here. This
+ // also avoids some cycles (e.g. #41849) since looking up
+ // variance requires computing types which can require
+ // performing trait matching (which then performs equality
+ // unification).
+
+ relate::relate_substs(self, None, a_subst, b_subst)
+ }
+
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
_: ty::Variance,
a: &T,
StorageDead(Lvalue<'tcx>),
InlineAsm {
- asm: InlineAsm,
+ asm: Box<InlineAsm>,
outputs: Vec<Lvalue<'tcx>>,
inputs: Vec<Operand<'tcx>>
},
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Operand<'tcx> {
Consume(Lvalue<'tcx>),
- Constant(Constant<'tcx>),
+ Constant(Box<Constant<'tcx>>),
}
impl<'tcx> Debug for Operand<'tcx> {
substs: &'tcx Substs<'tcx>,
span: Span,
) -> Self {
- Operand::Constant(Constant {
+ Operand::Constant(box Constant {
span: span,
ty: tcx.type_of(def_id).subst(tcx, substs),
literal: Literal::Value { value: ConstVal::Function(def_id, substs) },
/// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case
/// that `Foo` has a destructor. These rvalues can be optimized
/// away after type-checking and before lowering.
- Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>),
+ Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
tuple_fmt.finish()
}
- match *kind {
+ match **kind {
AggregateKind::Array(_) => write!(fmt, "{:?}", lvs),
AggregateKind::Tuple => {
Discriminant(ref lval) => Discriminant(lval.fold_with(folder)),
Box(ty) => Box(ty.fold_with(folder)),
Aggregate(ref kind, ref fields) => {
- let kind = match *kind {
+ let kind = box match **kind {
AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
AggregateKind::Tuple => AggregateKind::Tuple,
AggregateKind::Adt(def, v, substs, n) =>
Discriminant(ref lval) => lval.visit_with(visitor),
Box(ty) => ty.visit_with(visitor),
Aggregate(ref kind, ref fields) => {
- (match *kind {
+ (match **kind {
AggregateKind::Array(ty) => ty.visit_with(visitor),
AggregateKind::Tuple => false,
AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
tcx.mk_box(t)
}
Rvalue::Aggregate(ref ak, ref ops) => {
- match *ak {
+ match **ak {
AggregateKind::Array(ty) => {
tcx.mk_array(ty, ops.len())
}
Rvalue::Aggregate(ref $($mutability)* kind,
ref $($mutability)* operands) => {
+ let kind = &$($mutability)* **kind;
match *kind {
AggregateKind::Array(ref $($mutability)* ty) => {
self.visit_ty(ty);
pub empty_variance: Rc<Vec<ty::Variance>>,
}
+impl Variance {
+ /// `a.xform(b)` combines the variance of a context with the
+ /// variance of a type with the following meaning. If we are in a
+ /// context with variance `a`, and we encounter a type argument in
+ /// a position with variance `b`, then `a.xform(b)` is the new
+ /// variance with which the argument appears.
+ ///
+ /// Example 1:
+ ///
+ /// *mut Vec<i32>
+ ///
+ /// Here, the "ambient" variance starts as covariant. `*mut T` is
+ /// invariant with respect to `T`, so the variance in which the
+ /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
+ /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
+ /// respect to its type argument `T`, and hence the variance of
+ /// the `i32` here is `Invariant.xform(Covariant)`, which results
+ /// (again) in `Invariant`.
+ ///
+ /// Example 2:
+ ///
+ /// fn(*const Vec<i32>, *mut Vec<i32)
+ ///
+ /// The ambient variance is covariant. A `fn` type is
+ /// contravariant with respect to its parameters, so the variance
+ /// within which both pointer types appear is
+ /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
+ /// T` is covariant with respect to `T`, so the variance within
+ /// which the first `Vec<i32>` appears is
+ /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
+ /// is true for its `i32` argument. In the `*mut T` case, the
+ /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
+ /// and hence the outermost type is `Invariant` with respect to
+ /// `Vec<i32>` (and its `i32` argument).
+ ///
+ /// Source: Figure 1 of "Taming the Wildcards:
+ /// Combining Definition- and Use-Site Variance" published in PLDI'11.
+ pub fn xform(self, v: ty::Variance) -> ty::Variance {
+ match (self, v) {
+ // Figure 1, column 1.
+ (ty::Covariant, ty::Covariant) => ty::Covariant,
+ (ty::Covariant, ty::Contravariant) => ty::Contravariant,
+ (ty::Covariant, ty::Invariant) => ty::Invariant,
+ (ty::Covariant, ty::Bivariant) => ty::Bivariant,
+
+ // Figure 1, column 2.
+ (ty::Contravariant, ty::Covariant) => ty::Contravariant,
+ (ty::Contravariant, ty::Contravariant) => ty::Covariant,
+ (ty::Contravariant, ty::Invariant) => ty::Invariant,
+ (ty::Contravariant, ty::Bivariant) => ty::Bivariant,
+
+ // Figure 1, column 3.
+ (ty::Invariant, _) => ty::Invariant,
+
+ // Figure 1, column 4.
+ (ty::Bivariant, _) => ty::Bivariant,
+ }
+ }
+}
+
#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
pub struct MethodCallee<'tcx> {
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
Relate::relate(self, a, b)
}
+ /// Relate the two substitutions for the given item. The default
+ /// is to look up the variance for the item and proceed
+ /// accordingly.
+ fn relate_item_substs(&mut self,
+ item_def_id: DefId,
+ a_subst: &'tcx Substs<'tcx>,
+ b_subst: &'tcx Substs<'tcx>)
+ -> RelateResult<'tcx, &'tcx Substs<'tcx>>
+ {
+ debug!("relate_item_substs(item_def_id={:?}, a_subst={:?}, b_subst={:?})",
+ item_def_id,
+ a_subst,
+ b_subst);
+
+ let opt_variances = self.tcx().variances_of(item_def_id);
+ relate_substs(self, Some(&opt_variances), a_subst, b_subst)
+ }
+
/// Switch variance for the purpose of relating `a` and `b`.
fn relate_with_variance<T: Relate<'tcx>>(&mut self,
variance: ty::Variance,
}
}
-// substitutions are not themselves relatable without more context,
-// but they is an important subroutine for things that ARE relatable,
-// like traits etc.
-fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
- item_def_id: DefId,
- a_subst: &'tcx Substs<'tcx>,
- b_subst: &'tcx Substs<'tcx>)
- -> RelateResult<'tcx, &'tcx Substs<'tcx>>
- where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
-{
- debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}",
- item_def_id,
- a_subst,
- b_subst);
-
- let opt_variances = relation.tcx().variances_of(item_def_id);
- relate_substs(relation, Some(&opt_variances), a_subst, b_subst)
-}
-
pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
variances: Option<&Vec<ty::Variance>>,
a_subst: &'tcx Substs<'tcx>,
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
} else {
- let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
+ let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
}
}
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
} else {
- let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
+ let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs })
}
}
(&ty::TyAdt(a_def, a_substs), &ty::TyAdt(b_def, b_substs))
if a_def == b_def =>
{
- let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?;
+ let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?;
Ok(tcx.mk_adt(a_def, substs))
}
}
fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
- Rvalue::Use(Operand::Constant(Constant {
+ Rvalue::Use(Operand::Constant(Box::new(Constant {
span: span,
ty: self.tcx.types.bool,
literal: Literal::Value { value: ConstVal::Bool(val) }
- }))
+ })))
}
fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) {
node: ast::MetaItemKind::Word,
span: DUMMY_SP,
});
- if !allow_unstable_cfg && gated_cfg.is_some() {
- continue;
+
+ // Note that crt-static is a specially recognized cfg
+ // directive that's printed out here as part of
+ // rust-lang/rust#37406, but in general the
+ // `target_feature` cfg is gated under
+ // rust-lang/rust#29717. For now this is just
+ // specifically allowing the crt-static cfg and that's
+ // it, this is intended to get into Cargo and then go
+ // through to build scripts.
+ let value = value.as_ref().map(|s| s.as_str());
+ let value = value.as_ref().map(|s| s.as_ref());
+ if name != "target_feature" || value != Some("crt-static") {
+ if !allow_unstable_cfg && gated_cfg.is_some() {
+ continue;
+ }
}
- cfgs.push(if let &Some(ref value) = value {
+ cfgs.push(if let Some(value) = value {
format!("{}=\"{}\"", name, value)
} else {
format!("{}", name)
use llvm::LLVMRustHasFeature;
use rustc::session::Session;
use rustc_trans::back::write::create_target_machine;
-use syntax::feature_gate::UnstableFeatures;
use syntax::symbol::Symbol;
use libc::c_char;
}
let requested_features = sess.opts.cg.target_feature.split(',');
- let unstable_options = sess.opts.debugging_opts.unstable_options;
- let is_nightly = UnstableFeatures::from_environment().is_nightly_build();
let found_negative = requested_features.clone().any(|r| r == "-crt-static");
let found_positive = requested_features.clone().any(|r| r == "+crt-static");
found_positive
};
- // If we switched from the default then that's only allowed on nightly, so
- // gate that here.
- if (found_positive || found_negative) && (!is_nightly || !unstable_options) {
- sess.fatal("specifying the `crt-static` target feature is only allowed \
- on the nightly channel with `-Z unstable-options` passed \
- as well");
- }
-
if crt_static {
cfg.insert((tf, Some(Symbol::intern("crt-static"))));
}
// except according to those terms.
use CodeSuggestion;
+use Substitution;
use Level;
use RenderSpan;
use std::fmt;
pub code: Option<String>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
- pub suggestion: Option<CodeSuggestion>,
+ pub suggestions: Vec<CodeSuggestion>,
}
/// For example a note attached to an error.
code: code,
span: MultiSpan::new(),
children: vec![],
- suggestion: None,
+ suggestions: vec![],
}
}
///
/// See `diagnostic::CodeSuggestion` for more information.
pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
- assert!(self.suggestion.is_none());
- self.suggestion = Some(CodeSuggestion {
- msp: sp.into(),
- substitutes: vec![suggestion],
+ self.suggestions.push(CodeSuggestion {
+ substitution_parts: vec![Substitution {
+ span: sp,
+ substitutions: vec![suggestion],
+ }],
+ msg: msg.to_owned(),
+ });
+ self
+ }
+
+ pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
+ self.suggestions.push(CodeSuggestion {
+ substitution_parts: vec![Substitution {
+ span: sp,
+ substitutions: suggestions,
+ }],
msg: msg.to_owned(),
});
self
msg: &str,
suggestion: String)
-> &mut Self);
+ forward!(pub fn span_suggestions(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestions: Vec<String>)
+ -> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: String) -> &mut Self);
let mut primary_span = db.span.clone();
let mut children = db.children.clone();
- if let Some(sugg) = db.suggestion.clone() {
- assert_eq!(sugg.msp.primary_spans().len(), sugg.substitutes.len());
- // don't display multispans as labels
- if sugg.substitutes.len() == 1 &&
+ if let Some((sugg, rest)) = db.suggestions.split_first() {
+ if rest.is_empty() &&
+ // don't display multipart suggestions as labels
+ sugg.substitution_parts.len() == 1 &&
+ // don't display multi-suggestions as labels
+ sugg.substitutions() == 1 &&
// don't display long messages as labels
sugg.msg.split_whitespace().count() < 10 &&
// don't display multiline suggestions as labels
- sugg.substitutes[0].find('\n').is_none() {
- let msg = format!("help: {} `{}`", sugg.msg, sugg.substitutes[0]);
- primary_span.push_span_label(sugg.msp.primary_spans()[0], msg);
+ sugg.substitution_parts[0].substitutions[0].find('\n').is_none() {
+ let substitution = &sugg.substitution_parts[0].substitutions[0];
+ let msg = format!("help: {} `{}`", sugg.msg, substitution);
+ primary_span.push_span_label(sugg.substitution_spans().next().unwrap(), msg);
} else {
- children.push(SubDiagnostic {
- level: Level::Help,
- message: Vec::new(),
- span: MultiSpan::new(),
- render_span: Some(Suggestion(sugg)),
- });
+ // if there are multiple suggestions, print them all in full
+ // to be consistent. We could try to figure out if we can
+ // make one (or the first one) inline, but that would give
+ // undue importance to a semi-random suggestion
+ for sugg in &db.suggestions {
+ children.push(SubDiagnostic {
+ level: Level::Help,
+ message: Vec::new(),
+ span: MultiSpan::new(),
+ render_span: Some(Suggestion(sugg.clone())),
+ });
+ }
}
}
/// maximum number of lines we will print for each error; arbitrary.
pub const MAX_HIGHLIGHT_LINES: usize = 6;
+/// maximum number of suggestions to be shown
+///
+/// Arbitrary, but taken from trait import suggestion limit
+pub const MAX_SUGGESTIONS: usize = 4;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ColorConfig {
-> io::Result<()> {
use std::borrow::Borrow;
- let primary_span = suggestion.msp.primary_span().unwrap();
+ let primary_span = suggestion.substitution_spans().next().unwrap();
if let Some(ref cm) = self.cm {
let mut buffer = StyledBuffer::new();
- buffer.append(0, &level.to_string(), Style::Level(level.clone()));
- buffer.append(0, ": ", Style::HeaderMsg);
- self.msg_to_buffer(&mut buffer,
- &[(suggestion.msg.to_owned(), Style::NoStyle)],
- max_line_num_len,
- "suggestion",
- Some(Style::HeaderMsg));
-
let lines = cm.span_to_lines(primary_span).unwrap();
assert!(!lines.lines.is_empty());
- let complete = suggestion.splice_lines(cm.borrow());
+ buffer.append(0, &level.to_string(), Style::Level(level.clone()));
+ buffer.append(0, ": ", Style::HeaderMsg);
+ self.msg_to_buffer(&mut buffer,
+ &[(suggestion.msg.to_owned(), Style::NoStyle)],
+ max_line_num_len,
+ "suggestion",
+ Some(Style::HeaderMsg));
- // print the suggestion without any line numbers, but leave
- // space for them. This helps with lining up with previous
- // snippets from the actual error being reported.
- let mut lines = complete.lines();
+ let suggestions = suggestion.splice_lines(cm.borrow());
let mut row_num = 1;
- for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
- draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
- buffer.append(row_num, line, Style::NoStyle);
- row_num += 1;
- }
+ for complete in suggestions.iter().take(MAX_SUGGESTIONS) {
+
+ // print the suggestion without any line numbers, but leave
+ // space for them. This helps with lining up with previous
+ // snippets from the actual error being reported.
+ let mut lines = complete.lines();
+ for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
+ draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+ buffer.append(row_num, line, Style::NoStyle);
+ row_num += 1;
+ }
- // if we elided some lines, add an ellipsis
- if let Some(_) = lines.next() {
- buffer.append(row_num, "...", Style::NoStyle);
+ // if we elided some lines, add an ellipsis
+ if let Some(_) = lines.next() {
+ buffer.append(row_num, "...", Style::NoStyle);
+ }
+ }
+ if suggestions.len() > MAX_SUGGESTIONS {
+ let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
+ buffer.append(row_num, &msg, Style::NoStyle);
}
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
}
#![feature(staged_api)]
#![feature(range_contains)]
#![feature(libc)]
+#![feature(conservative_impl_trait)]
extern crate term;
extern crate libc;
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct CodeSuggestion {
- pub msp: MultiSpan,
- pub substitutes: Vec<String>,
+ /// Each substitute can have multiple variants due to multiple
+ /// applicable suggestions
+ ///
+ /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
+ /// `foo` and `bar` on their own:
+ ///
+ /// ```
+ /// vec![
+ /// (0..3, vec!["a", "x"]),
+ /// (4..7, vec!["b", "y"]),
+ /// ]
+ /// ```
+ ///
+ /// or by replacing the entire span:
+ ///
+ /// ```
+ /// vec![(0..7, vec!["a.b", "x.y"])]
+ /// ```
+ pub substitution_parts: Vec<Substitution>,
pub msg: String,
}
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
+/// See the docs on `CodeSuggestion::substitutions`
+pub struct Substitution {
+ pub span: Span,
+ pub substitutions: Vec<String>,
+}
+
pub trait CodeMapper {
fn lookup_char_pos(&self, pos: BytePos) -> Loc;
fn span_to_lines(&self, sp: Span) -> FileLinesResult;
}
impl CodeSuggestion {
- /// Returns the assembled code suggestion.
- pub fn splice_lines(&self, cm: &CodeMapper) -> String {
+ /// Returns the number of substitutions
+ fn substitutions(&self) -> usize {
+ self.substitution_parts[0].substitutions.len()
+ }
+
+ /// Returns the number of substitutions
+ pub fn substitution_spans<'a>(&'a self) -> impl Iterator<Item = Span> + 'a {
+ self.substitution_parts.iter().map(|sub| sub.span)
+ }
+
+ /// Returns the assembled code suggestions.
+ pub fn splice_lines(&self, cm: &CodeMapper) -> Vec<String> {
use syntax_pos::{CharPos, Loc, Pos};
fn push_trailing(buf: &mut String,
}
}
- let mut primary_spans = self.msp.primary_spans().to_owned();
-
- assert_eq!(primary_spans.len(), self.substitutes.len());
- if primary_spans.is_empty() {
- return format!("");
+ if self.substitution_parts.is_empty() {
+ return vec![String::new()];
}
+ let mut primary_spans: Vec<_> = self.substitution_parts
+ .iter()
+ .map(|sub| (sub.span, &sub.substitutions))
+ .collect();
+
// Assumption: all spans are in the same file, and all spans
// are disjoint. Sort in ascending order.
- primary_spans.sort_by_key(|sp| sp.lo);
+ primary_spans.sort_by_key(|sp| sp.0.lo);
// Find the bounding span.
- let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
- let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
+ let lo = primary_spans.iter().map(|sp| sp.0.lo).min().unwrap();
+ let hi = primary_spans.iter().map(|sp| sp.0.hi).min().unwrap();
let bounding_span = Span {
lo: lo,
hi: hi,
prev_hi.col = CharPos::from_usize(0);
let mut prev_line = fm.get_line(lines.lines[0].line_index);
- let mut buf = String::new();
+ let mut bufs = vec![String::new(); self.substitutions()];
- for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
+ for (sp, substitutes) in primary_spans {
let cur_lo = cm.lookup_char_pos(sp.lo);
- if prev_hi.line == cur_lo.line {
- push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
- } else {
- push_trailing(&mut buf, prev_line, &prev_hi, None);
- // push lines between the previous and current span (if any)
- for idx in prev_hi.line..(cur_lo.line - 1) {
- if let Some(line) = fm.get_line(idx) {
- buf.push_str(line);
- buf.push('\n');
+ for (buf, substitute) in bufs.iter_mut().zip(substitutes) {
+ if prev_hi.line == cur_lo.line {
+ push_trailing(buf, prev_line, &prev_hi, Some(&cur_lo));
+ } else {
+ push_trailing(buf, prev_line, &prev_hi, None);
+ // push lines between the previous and current span (if any)
+ for idx in prev_hi.line..(cur_lo.line - 1) {
+ if let Some(line) = fm.get_line(idx) {
+ buf.push_str(line);
+ buf.push('\n');
+ }
+ }
+ if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
+ buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
}
}
- if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
- buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
- }
+ buf.push_str(substitute);
}
- buf.push_str(substitute);
prev_hi = cm.lookup_char_pos(sp.hi);
prev_line = fm.get_line(prev_hi.line - 1);
}
- push_trailing(&mut buf, prev_line, &prev_hi, None);
- // remove trailing newline
- buf.pop();
- buf
+ for buf in &mut bufs {
+ // if the replacement already ends with a newline, don't print the next line
+ if !buf.ends_with('\n') {
+ push_trailing(buf, prev_line, &prev_hi, None);
+ }
+ // remove trailing newline
+ buf.pop();
+ }
+ bufs
}
}
temp: &Lvalue<'tcx>,
constant: Constant<'tcx>) {
self.push_assign(block, source_info, temp,
- Rvalue::Use(Operand::Constant(constant)));
+ Rvalue::Use(Operand::Constant(box constant)));
}
pub fn push_assign_unit(&mut self,
source_info: SourceInfo,
lvalue: &Lvalue<'tcx>) {
self.push_assign(block, source_info, lvalue, Rvalue::Aggregate(
- AggregateKind::Tuple, vec![]
+ box AggregateKind::Tuple, vec![]
));
}
match category {
Category::Constant => {
let constant = this.as_constant(expr);
- block.and(Operand::Constant(constant))
+ block.and(Operand::Constant(box constant))
}
Category::Lvalue |
Category::Rvalue(..) => {
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
.collect();
- block.and(Rvalue::Aggregate(AggregateKind::Array(el_ty), fields))
+ block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
}
ExprKind::Tuple { fields } => { // see (*) above
// first process the set of fields
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
.collect();
- block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields))
+ block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
}
ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above
let upvars =
upvars.into_iter()
.map(|upvar| unpack!(block = this.as_operand(block, scope, upvar)))
.collect();
- block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
+ block.and(Rvalue::Aggregate(box AggregateKind::Closure(closure_id, substs), upvars))
}
ExprKind::Adt {
adt_def, variant_index, substs, fields, base
field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
};
- let adt = AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
+ let adt =
+ box AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
block.and(Rvalue::Aggregate(adt, fields))
}
ExprKind::Assign { .. } |
this.cfg.push(block, Statement {
source_info: source_info,
kind: StatementKind::InlineAsm {
- asm: asm.clone(),
+ asm: box asm.clone(),
outputs: outputs,
inputs: inputs
},
let eq_block = self.cfg.start_new_block();
let cleanup = self.diverge_cleanup();
self.cfg.terminate(block, source_info, TerminatorKind::Call {
- func: Operand::Constant(Constant {
+ func: Operand::Constant(box Constant {
span: test.span,
ty: mty,
literal: method
ty: Ty<'tcx>,
literal: Literal<'tcx>)
-> Operand<'tcx> {
- let constant = Constant {
+ let constant = box Constant {
span: span,
ty: ty,
literal: literal,
}
pub fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
- Rvalue::Aggregate(AggregateKind::Tuple, vec![])
+ Rvalue::Aggregate(box AggregateKind::Tuple, vec![])
}
// Returns a zero literal operand for the appropriate type, works for
let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]);
TerminatorKind::Call {
- func: Operand::Constant(Constant {
+ func: Operand::Constant(box Constant {
span: data.span,
ty: tcx.type_of(free_func).subst(tcx, substs),
literal: Literal::Value {
let (callee, mut args) = match call_kind {
CallKind::Indirect => (rcvr, vec![]),
CallKind::Direct(def_id) => (
- Operand::Constant(Constant {
+ Operand::Constant(box Constant {
span: span,
ty: tcx.type_of(def_id).subst(tcx, param_env.free_substs),
literal: Literal::Value {
kind: StatementKind::Assign(
Lvalue::Local(RETURN_POINTER),
Rvalue::Aggregate(
- AggregateKind::Adt(adt_def, variant_no, substs, None),
+ box AggregateKind::Adt(adt_def, variant_no, substs, None),
(1..sig.inputs().len()+1).map(|i| {
Operand::Consume(Lvalue::Local(Local::new(i)))
}).collect()
_ => return,
}
- *operand = Operand::Constant(self.constant.clone());
+ *operand = Operand::Constant(box self.constant.clone());
self.uses_replaced += 1
}
}
&Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands),
_ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
};
- let (adt_def, variant, substs) = match agg_kind {
- &AggregateKind::Adt(adt_def, variant, substs, None)
+ let (adt_def, variant, substs) = match **agg_kind {
+ AggregateKind::Adt(adt_def, variant, substs, None)
=> (adt_def, variant, substs),
_ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
};
&Rvalue::Aggregate(ref kind, ref operands) => (kind, operands),
_ => continue,
};
- let (adt_def, variant) = match kind {
- &AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
+ let (adt_def, variant) = match **kind {
+ AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
_ => continue,
};
if operands.len() == 0 {
(if self.keep_original {
rhs.clone()
} else {
- let unit = Rvalue::Aggregate(AggregateKind::Tuple, vec![]);
+ let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
mem::replace(rhs, unit)
}, statement.source_info)
};
fn promote_candidate(mut self, candidate: Candidate) {
let span = self.promoted.span;
- let new_operand = Operand::Constant(Constant {
+ let new_operand = Operand::Constant(box Constant {
span: span,
ty: self.promoted.return_ty,
literal: Literal::Promoted {
}
Rvalue::Aggregate(ref kind, _) => {
- if let AggregateKind::Adt(def, ..) = *kind {
+ if let AggregateKind::Adt(def, ..) = **kind {
if def.has_dtor(self.tcx) {
self.add(Qualif::NEEDS_DROP);
self.deny_drop();
for block in mir.basic_blocks_mut() {
let terminator = block.terminator_mut();
terminator.kind = match terminator.kind {
- TerminatorKind::SwitchInt { discr: Operand::Constant(Constant {
+ TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
literal: Literal::Value { ref value }, ..
}), ref values, ref targets, .. } => {
if let Some(ref constint) = value.to_const_int() {
continue
}
},
- TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
+ TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
literal: Literal::Value {
value: ConstVal::Bool(cond)
}, ..
}
}
}
-
fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
match operand {
- &Operand::Constant(Constant {
+ &Operand::Constant(box Constant {
literal: Literal::Value {
value: ConstVal::Function(def_id, _), ..
}, ..
Rvalue::Aggregate(ref kind, ref _operands) => {
// AggregateKind is not distinguished by visit API, so
// record it. (`super_rvalue` handles `_operands`.)
- self.record(match *kind {
+ self.record(match **kind {
AggregateKind::Array(_) => "AggregateKind::Array",
AggregateKind::Tuple => "AggregateKind::Tuple",
AggregateKind::Adt(..) => "AggregateKind::Adt",
view_path.span,
ResolutionError::SelfImportsOnlyAllowedWithin);
} else if source_name == "$crate" && full_path.segments.len() == 1 {
- let crate_root = self.resolve_crate_var(source.ctxt);
+ let crate_root = self.resolve_crate_var(source.ctxt, item.span);
let crate_name = match crate_root.kind {
ModuleKind::Def(_, name) => name,
ModuleKind::Block(..) => unreachable!(),
// n.b. we don't need to look at the path option here, because cstore already did
let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
- let module = self.get_extern_crate_root(crate_id);
+ let module = self.get_extern_crate_root(crate_id, item.span);
self.populate_module_if_necessary(module);
let used = self.process_legacy_macro_imports(item, module, expansion);
let binding =
no_implicit_prelude: parent.no_implicit_prelude || {
attr::contains_name(&item.attrs, "no_implicit_prelude")
},
- ..ModuleData::new(Some(parent), module_kind, def_id)
+ ..ModuleData::new(Some(parent), module_kind, def_id, item.span)
});
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.module_map.insert(def_id, module);
ItemKind::Enum(ref enum_definition, _) => {
let def = Def::Enum(self.definitions.local_def_id(item.id));
let module_kind = ModuleKind::Def(def, ident.name);
- let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+ let module = self.new_module(parent,
+ module_kind,
+ parent.normal_ancestor_id,
+ item.span);
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
for variant in &(*enum_definition).variants {
// Add all the items within to a new module.
let module_kind = ModuleKind::Def(Def::Trait(def_id), ident.name);
- let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+ let module = self.new_module(parent,
+ module_kind,
+ parent.normal_ancestor_id,
+ item.span);
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.current_module = module;
}
fn build_reduced_graph_for_block(&mut self, block: &Block) {
let parent = self.current_module;
if self.block_needs_anonymous_module(block) {
- let module =
- self.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id);
+ let module = self.new_module(parent,
+ ModuleKind::Block(block.id),
+ parent.normal_ancestor_id,
+ block.span);
self.block_map.insert(block.id, module);
self.current_module = module; // Descend into the block.
}
let def = child.def;
let def_id = def.def_id();
let vis = self.session.cstore.visibility(def_id);
+ let span = child.span;
match def {
Def::Mod(..) | Def::Enum(..) => {
- let module = self.new_module(parent, ModuleKind::Def(def, ident.name), def_id);
+ let module = self.new_module(parent,
+ ModuleKind::Def(def, ident.name),
+ def_id,
+ span);
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
}
Def::Variant(..) | Def::TyAlias(..) => {
}
Def::Trait(..) => {
let module_kind = ModuleKind::Def(def, ident.name);
- let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
+ let module = self.new_module(parent,
+ module_kind,
+ parent.normal_ancestor_id,
+ span);
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
for child in self.session.cstore.item_children(def_id) {
}
}
- fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'a> {
+ fn get_extern_crate_root(&mut self, cnum: CrateNum, span: Span) -> Module<'a> {
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
let name = self.session.cstore.crate_name(cnum);
let macros_only = self.session.cstore.dep_kind(cnum).macros_only();
let module_kind = ModuleKind::Def(Def::Mod(def_id), name);
let arenas = self.arenas;
*self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
- arenas.alloc_module(ModuleData::new(None, module_kind, def_id))
+ arenas.alloc_module(ModuleData::new(None, module_kind, def_id, span))
})
}
- pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
+ pub fn macro_def_scope(&mut self, expansion: Mark, span: Span) -> Module<'a> {
let def_id = self.macro_defs[&expansion];
if let Some(id) = self.definitions.as_local_node_id(def_id) {
self.local_macro_def_scopes[&id]
self.graph_root
} else {
let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
- self.get_extern_crate_root(module_def_id.krate)
+ self.get_extern_crate_root(module_def_id.krate, span)
}
}
} else {
for (name, span) in legacy_imports.imports {
let ident = Ident::with_empty_ctxt(name);
- let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
+ let result = self.resolve_ident_in_module(module, ident, MacroNS,
+ false, false, span);
if let Ok(binding) = result {
let directive = macro_use_directive(span);
self.potentially_unused_imports.push(directive);
for (name, span) in legacy_imports.reexports {
self.session.cstore.export_macros(module.def_id().unwrap().krate);
let ident = Ident::with_empty_ctxt(name);
- let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
+ let result = self.resolve_ident_in_module(module, ident, MacroNS, false, false, span);
if let Ok(binding) = result {
self.macro_exports.push(Export { name: name, def: binding.def(), span: span });
} else {
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
} else if let TyKind::ImplicitSelf = ty.node {
let self_ty = keywords::SelfType.ident();
- let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
+ let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, true, ty.span)
.map_or(Def::Err, |d| d.def());
self.record_def(ty.id, PathResolution::new(def));
} else if let TyKind::Array(ref element, ref length) = ty.node {
// access the children must be preceded with a
// `populate_module_if_necessary` call.
populated: Cell<bool>,
+
+ /// Span of the module itself. Used for error reporting.
+ span: Span,
}
pub type Module<'a> = &'a ModuleData<'a>;
impl<'a> ModuleData<'a> {
- fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId) -> Self {
+ fn new(parent: Option<Module<'a>>,
+ kind: ModuleKind,
+ normal_ancestor_id: DefId,
+ span: Span) -> Self {
ModuleData {
parent: parent,
kind: kind,
globs: RefCell::new((Vec::new())),
traits: RefCell::new(None),
populated: Cell::new(normal_ancestor_id.is_local()),
+ span: span,
}
}
let namespace = if is_value { ValueNS } else { TypeNS };
let hir::Path { ref segments, span, ref mut def } = *path;
let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect();
- match self.resolve_path(&path, Some(namespace), Some(span)) {
+ match self.resolve_path(&path, Some(namespace), true, span) {
PathResult::Module(module) => *def = module.def().unwrap(),
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
*def = path_res.base_def(),
- PathResult::NonModule(..) => match self.resolve_path(&path, None, Some(span)) {
+ PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) {
PathResult::Failed(msg, _) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
}
let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
let graph_root = arenas.alloc_module(ModuleData {
no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
- ..ModuleData::new(None, root_module_kind, root_def_id)
+ ..ModuleData::new(None, root_module_kind, root_def_id, krate.span)
});
let mut module_map = FxHashMap();
module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
self.crate_loader.postprocess(krate);
}
- fn new_module(&self, parent: Module<'a>, kind: ModuleKind, normal_ancestor_id: DefId)
- -> Module<'a> {
- self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id))
+ fn new_module(
+ &self,
+ parent: Module<'a>,
+ kind: ModuleKind,
+ normal_ancestor_id: DefId,
+ span: Span,
+ ) -> Module<'a> {
+ self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id, span))
}
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
fn resolve_ident_in_lexical_scope(&mut self,
mut ident: Ident,
ns: Namespace,
- record_used: Option<Span>)
+ record_used: bool,
+ path_span: Span)
-> Option<LexicalScopeBinding<'a>> {
if ns == TypeNS {
ident = ident.unhygienize();
if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::Def(
- self.adjust_local_def(ns, i, def, record_used)
+ self.adjust_local_def(ns, i, def, record_used, path_span)
));
}
if let ModuleRibKind(module) = self.ribs[ns][i].kind {
- let item = self.resolve_ident_in_module(module, ident, ns, false, record_used);
+ let item = self.resolve_ident_in_module(module, ident, ns, false,
+ record_used, path_span);
if let Ok(binding) = item {
// The ident resolves to an item.
return Some(LexicalScopeBinding::Item(binding));
if let ModuleKind::Block(..) = module.kind { // We can see through blocks
} else if !module.no_implicit_prelude {
return self.prelude.and_then(|prelude| {
- self.resolve_ident_in_module(prelude, ident, ns, false, None).ok()
+ self.resolve_ident_in_module(prelude, ident, ns, false,
+ false, path_span).ok()
}).map(LexicalScopeBinding::Item)
} else {
return None;
None
}
- fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> {
+ fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext, span: Span) -> Module<'a> {
let mut ctxt_data = crate_var_ctxt.data();
while ctxt_data.prev_ctxt != SyntaxContext::empty() {
ctxt_data = ctxt_data.prev_ctxt.data();
}
- let module = self.macro_def_scope(ctxt_data.outer_mark);
+ let module = self.macro_def_scope(ctxt_data.outer_mark, span);
if module.is_local() { self.graph_root } else { module }
}
PatKind::Ident(bmode, ref ident, ref opt_pat) => {
// First try to resolve the identifier as some existing
// entity, then fall back to a fresh binding.
- let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None)
+ let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS,
+ false, pat.span)
.and_then(LexicalScopeBinding::item);
let resolution = binding.map(NameBinding::def).and_then(|def| {
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
(format!(""), format!("the crate root"))
} else {
let mod_path = &path[..path.len() - 1];
- let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), None) {
+ let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), false, span) {
PathResult::Module(module) => module.def(),
_ => None,
}.map_or(format!(""), |def| format!("{} ", def.kind_name()));
let name = path.last().unwrap().name;
let candidates = this.lookup_import_candidates(name, ns, is_expected);
if !candidates.is_empty() {
+ let mut module_span = this.current_module.span;
+ module_span.hi = module_span.lo;
// Report import candidates as help and proceed searching for labels.
- show_candidates(&mut err, &candidates, def.is_some());
+ show_candidates(&mut err, module_span, &candidates, def.is_some());
} else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant);
let mut enum_candidates = enum_candidates.iter()
}
}
}
- if path.len() == 1 && this.self_type_is_available() {
+ if path.len() == 1 && this.self_type_is_available(span) {
if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
- let self_is_available = this.self_value_is_available(path[0].ctxt);
+ let self_is_available = this.self_value_is_available(path[0].ctxt, span);
match candidate {
AssocSuggestion::Field => {
err.span_label(span, format!("did you mean `self.{}`?", path_str));
let mut levenshtein_worked = false;
// Try Levenshtein.
- if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) {
+ if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected, span) {
err.span_label(ident_span, format!("did you mean `{}`?", candidate));
levenshtein_worked = true;
}
resolution
}
- fn self_type_is_available(&mut self) -> bool {
- let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(), TypeNS, None);
+ fn self_type_is_available(&mut self, span: Span) -> bool {
+ let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(),
+ TypeNS, false, span);
if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
}
- fn self_value_is_available(&mut self, ctxt: SyntaxContext) -> bool {
+ fn self_value_is_available(&mut self, ctxt: SyntaxContext, span: Span) -> bool {
let ident = Ident { name: keywords::SelfValue.name(), ctxt: ctxt };
- let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None);
+ let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, false, span);
if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
}
));
}
- let result = match self.resolve_path(&path, Some(ns), Some(span)) {
+ let result = match self.resolve_path(&path, Some(ns), true, span) {
PathResult::NonModule(path_res) => path_res,
PathResult::Module(module) if !module.is_normal() => {
PathResolution::new(module.def().unwrap())
if path.len() > 1 && !global_by_default && result.base_def() != Def::Err &&
path[0].name != keywords::CrateRoot.name() && path[0].name != "$crate" {
let unqualified_result = {
- match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
+ match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) {
PathResult::NonModule(path_res) => path_res.base_def(),
PathResult::Module(module) => module.def().unwrap(),
_ => return Some(result),
fn resolve_path(&mut self,
path: &[Ident],
opt_ns: Option<Namespace>, // `None` indicates a module path
- record_used: Option<Span>)
+ record_used: bool,
+ path_span: Span)
-> PathResult<'a> {
let mut module = None;
let mut allow_super = true;
module = Some(self.graph_root);
continue
} else if i == 0 && ns == TypeNS && ident.name == "$crate" {
- module = Some(self.resolve_crate_var(ident.ctxt));
+ module = Some(self.resolve_crate_var(ident.ctxt, path_span));
continue
}
let binding = if let Some(module) = module {
- self.resolve_ident_in_module(module, ident, ns, false, record_used)
+ self.resolve_ident_in_module(module, ident, ns, false, record_used, path_span)
} else if opt_ns == Some(MacroNS) {
- self.resolve_lexical_macro_path_segment(ident, ns, record_used)
+ self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span)
.map(MacroBinding::binding)
} else {
- match self.resolve_ident_in_lexical_scope(ident, ns, record_used) {
+ match self.resolve_ident_in_lexical_scope(ident, ns, record_used, path_span) {
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
Some(LexicalScopeBinding::Def(def))
if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => {
def, path.len() - 1
));
}
- _ => Err(if record_used.is_some() { Determined } else { Undetermined }),
+ _ => Err(if record_used { Determined } else { Undetermined }),
}
};
ns: Namespace,
rib_index: usize,
mut def: Def,
- record_used: Option<Span>) -> Def {
+ record_used: bool,
+ span: Span) -> Def {
let ribs = &self.ribs[ns][rib_index + 1..];
// An invalid forward use of a type parameter from a previous default.
if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
- if let Some(span) = record_used {
+ if record_used {
resolve_error(self, span,
ResolutionError::ForwardDeclaredTyParam);
}
match def {
Def::Upvar(..) => {
- span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
+ span_bug!(span, "unexpected {:?} in bindings", def)
}
Def::Local(def_id) => {
for rib in ribs {
let depth = vec.len();
def = Def::Upvar(def_id, depth, function_id);
- if let Some(span) = record_used {
+ if record_used {
vec.push(Freevar {
def: prev_def,
span: span,
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
// report an error.
- if let Some(span) = record_used {
+ if record_used {
resolve_error(self, span,
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
}
}
ConstantItemRibKind => {
// Still doesn't deal with upvars
- if let Some(span) = record_used {
+ if record_used {
resolve_error(self, span,
ResolutionError::AttemptToUseNonConstantValueInConstant);
}
ItemRibKind => {
// This was an attempt to use a type parameter outside
// its scope.
- if let Some(span) = record_used {
+ if record_used {
resolve_error(self, span,
ResolutionError::TypeParametersFromOuterFunction);
}
}
ConstantItemRibKind => {
// see #9186
- if let Some(span) = record_used {
+ if record_used {
resolve_error(self, span,
ResolutionError::OuterTypeParameterContext);
}
fn lookup_typo_candidate<FilterFn>(&mut self,
path: &[Ident],
ns: Namespace,
- filter_fn: FilterFn)
+ filter_fn: FilterFn,
+ span: Span)
-> Option<Symbol>
where FilterFn: Fn(Def) -> bool
{
} else {
// Search in module.
let mod_path = &path[..path.len() - 1];
- if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), None) {
+ if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS),
+ false, span) {
add_module_candidates(module, &mut names);
}
}
continue
}
let ident = attr.path.segments[0].identifier;
- let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None);
+ let result = self.resolve_lexical_macro_path_segment(ident,
+ MacroNS,
+ false,
+ attr.path.span);
if let Ok(binding) = result {
if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) {
attr::mark_known(attr);
/// When an entity with a given name is not available in scope, we search for
/// entities with that name in all crates. This method allows outputting the
/// results of this search in a programmer-friendly way
-fn show_candidates(session: &mut DiagnosticBuilder,
+fn show_candidates(err: &mut DiagnosticBuilder,
+ span: Span,
candidates: &[ImportSuggestion],
better: bool) {
- // don't show more than MAX_CANDIDATES results, so
- // we're consistent with the trait suggestions
- const MAX_CANDIDATES: usize = 4;
// we want consistent results across executions, but candidates are produced
// by iterating through a hash map, so make sure they are ordered:
1 => " is found in another module, you can import it",
_ => "s are found in other modules, you can import them",
};
+ let msg = format!("possible {}candidate{} into scope", better, msg_diff);
+
+ for candidate in &mut path_strings {
+ *candidate = format!("use {};\n", candidate);
+ }
- let end = cmp::min(MAX_CANDIDATES, path_strings.len());
- session.help(&format!("possible {}candidate{} into scope:{}{}",
- better,
- msg_diff,
- &path_strings[0..end].iter().map(|candidate| {
- format!("\n `use {};`", candidate)
- }).collect::<String>(),
- if path_strings.len() > MAX_CANDIDATES {
- format!("\nand {} other candidates",
- path_strings.len() - MAX_CANDIDATES)
- } else {
- "".to_owned()
- }
- ));
+ err.span_suggestions(span, &msg, path_strings);
}
/// A somewhat inefficient routine to obtain the name of a module.
}
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> {
- struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>);
+ struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>, Span);
impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> {
fn fold_path(&mut self, mut path: ast::Path) -> ast::Path {
let ident = path.segments[0].identifier;
if ident.name == "$crate" {
path.segments[0].identifier.name = keywords::CrateRoot.name();
- let module = self.0.resolve_crate_var(ident.ctxt);
+ let module = self.0.resolve_crate_var(ident.ctxt, self.1);
if !module.is_local() {
let span = path.segments[0].span;
path.segments.insert(1, match module.kind {
}
}
- EliminateCrateVar(self).fold_item(item).expect_one("")
+ EliminateCrateVar(self, item.span).fold_item(item).expect_one("")
}
fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool {
return Err(Determinacy::Determined);
}
- let def = match self.resolve_path(&path, Some(MacroNS), None) {
+ let def = match self.resolve_path(&path, Some(MacroNS), false, span) {
PathResult::NonModule(path_res) => match path_res.base_def() {
Def::Err => Err(Determinacy::Determined),
def @ _ => Ok(def),
let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
Ok(Def::Macro(binding.def_id, MacroKind::Bang))
} else {
- match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) {
+ match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, span) {
Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()),
Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
Err(_) => {
pub fn resolve_lexical_macro_path_segment(&mut self,
ident: Ident,
ns: Namespace,
- record_used: Option<Span>)
+ record_used: bool,
+ path_span: Span)
-> Result<MacroBinding<'a>, Determinacy> {
let mut module = Some(self.current_module);
let mut potential_illegal_shadower = Err(Determinacy::Determined);
let determinacy =
- if record_used.is_some() { Determinacy::Determined } else { Determinacy::Undetermined };
+ if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
loop {
let result = if let Some(module) = module {
// Since expanded macros may not shadow the lexical scope and
// globs may not shadow global macros (both enforced below),
// we resolve with restricted shadowing (indicated by the penultimate argument).
- self.resolve_ident_in_module(module, ident, ns, true, record_used)
+ self.resolve_ident_in_module(module, ident, ns, true, record_used, path_span)
.map(MacroBinding::Modern)
} else {
self.global_macros.get(&ident.name).cloned().ok_or(determinacy)
match result.map(MacroBinding::binding) {
Ok(binding) => {
- let span = match record_used {
- Some(span) => span,
- None => return result,
- };
+ if !record_used {
+ return result;
+ }
if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower {
if shadower.def() != binding.def() {
let name = ident.name;
self.ambiguity_errors.push(AmbiguityError {
- span: span, name: name, b1: shadower, b2: binding, lexical: true,
+ span: path_span,
+ name: name,
+ b1: shadower,
+ b2: binding,
+ lexical: true,
legacy: false,
});
return potential_illegal_shadower;
pub fn finalize_current_module_macro_resolutions(&mut self) {
let module = self.current_module;
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
- match self.resolve_path(path, Some(MacroNS), Some(span)) {
+ match self.resolve_path(path, Some(MacroNS), true, span) {
PathResult::NonModule(_) => {},
PathResult::Failed(msg, _) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() {
let legacy_scope = &self.invocations[&mark].legacy_scope;
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true);
- let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span));
+ let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span);
match (legacy_resolution, resolution) {
(Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
let msg1 = format!("`{}` could refer to the macro defined here", ident);
format!("cannot find derive macro `{}` in this scope", ident),
};
let mut err = self.session.struct_span_err(span, &msg);
- self.suggest_macro_name(&ident.name.as_str(), kind, &mut err);
+ self.suggest_macro_name(&ident.name.as_str(), kind, &mut err, span);
err.emit();
},
_ => {},
}
fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
- err: &mut DiagnosticBuilder<'a>) {
+ err: &mut DiagnosticBuilder<'a>, span: Span) {
// First check if this is a locally-defined bang macro.
let suggestion = if let MacroKind::Bang = kind {
find_best_match_for_name(self.macro_names.iter(), name, None)
}
};
let ident = Ident::from_str(name);
- self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro)
+ self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro, span)
});
if let Some(suggestion) = suggestion {
ident: Ident,
ns: Namespace,
restricted_shadowing: bool,
- record_used: Option<Span>)
+ record_used: bool,
+ path_span: Span)
-> Result<&'a NameBinding<'a>, Determinacy> {
self.populate_module_if_necessary(module);
.try_borrow_mut()
.map_err(|_| Determined)?; // This happens when there is a cycle of imports
- if let Some(span) = record_used {
+ if record_used {
if let Some(binding) = resolution.binding {
if let Some(shadowed_glob) = resolution.shadows_glob {
let name = ident.name;
ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing
binding.def() != shadowed_glob.def() {
self.ambiguity_errors.push(AmbiguityError {
- span: span, name: name, lexical: false, b1: binding, b2: shadowed_glob,
+ span: path_span,
+ name: name,
+ lexical: false,
+ b1: binding,
+ b2: shadowed_glob,
legacy: false,
});
}
}
- if self.record_use(ident, ns, binding, span) {
+ if self.record_use(ident, ns, binding, path_span) {
return Ok(self.dummy_binding);
}
if !self.is_accessible(binding.vis) {
- self.privacy_errors.push(PrivacyError(span, ident.name, binding));
+ self.privacy_errors.push(PrivacyError(path_span, ident.name, binding));
}
}
SingleImport { source, .. } => source,
_ => unreachable!(),
};
- match self.resolve_ident_in_module(module, ident, ns, false, None) {
+ match self.resolve_ident_in_module(module, ident, ns, false, false, path_span) {
Err(Determined) => {}
_ => return Err(Undetermined),
}
for directive in module.globs.borrow().iter() {
if self.is_accessible(directive.vis.get()) {
if let Some(module) = directive.imported_module.get() {
- let result = self.resolve_ident_in_module(module, ident, ns, false, None);
+ let result = self.resolve_ident_in_module(module,
+ ident,
+ ns,
+ false,
+ false,
+ path_span);
if let Err(Undetermined) = result {
return Err(Undetermined);
}
// For better failure detection, pretend that the import will not define any names
// while resolving its module path.
directive.vis.set(ty::Visibility::Invisible);
- let result = self.resolve_path(&directive.module_path, None, None);
+ let result = self.resolve_path(&directive.module_path, None, false, directive.span);
directive.vis.set(vis);
match result {
let mut indeterminate = false;
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
if let Err(Undetermined) = result[ns].get() {
- result[ns].set(this.resolve_ident_in_module(module, source, ns, false, None));
+ result[ns].set(this.resolve_ident_in_module(module,
+ source,
+ ns,
+ false,
+ false,
+ directive.span));
} else {
return
};
self.current_module = directive.parent;
let ImportDirective { ref module_path, span, .. } = *directive;
- let module_result = self.resolve_path(&module_path, None, Some(span));
+ let module_result = self.resolve_path(&module_path, None, true, span);
let module = match module_result {
PathResult::Module(module) => module,
PathResult::Failed(msg, _) => {
let (mut self_path, mut self_result) = (module_path.clone(), None);
if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() {
self_path[0].name = keywords::SelfValue.name();
- self_result = Some(self.resolve_path(&self_path, None, None));
+ self_result = Some(self.resolve_path(&self_path, None, false, span));
}
return if let Some(PathResult::Module(..)) = self_result {
Some(format!("Did you mean `{}`?", names_to_string(&self_path)))
Some(this.dummy_binding);
}
}
- } else if let Ok(binding) = this.resolve_ident_in_module(module, ident, ns, false, None) {
+ } else if let Ok(binding) = this.resolve_ident_in_module(module,
+ ident,
+ ns,
+ false,
+ false,
+ directive.span) {
legacy_self_import = Some(directive);
let binding = this.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Import {
}
let mut all_ns_failed = true;
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
- match this.resolve_ident_in_module(module, ident, ns, false, Some(span)) {
+ match this.resolve_ident_in_module(module, ident, ns, false, true, span) {
Ok(_) => all_ns_failed = false,
_ => {}
}
location: Location) {
match *kind {
mir::TerminatorKind::Call {
- func: mir::Operand::Constant(mir::Constant {
+ func: mir::Operand::Constant(box mir::Constant {
literal: Literal::Value {
value: ConstVal::Function(def_id, _), ..
}, ..
}
failure?;
- match *kind {
+ match **kind {
mir::AggregateKind::Array(_) => {
self.const_array(dest_ty, &fields)
}
}
mir::Rvalue::Aggregate(ref kind, ref operands) => {
- match *kind {
+ match **kind {
mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
let discr = adt_def.discriminant_for_variant(bcx.tcx(), variant_index)
.to_u128_unchecked() as u64;
use super::terms::*;
use super::terms::VarianceTerm::*;
-use super::xform::*;
pub struct ConstraintContext<'a, 'tcx: 'a> {
pub terms_cx: TermsContext<'a, 'tcx>,
use rustc::ty;
-pub trait Xform {
- fn xform(self, v: Self) -> Self;
-}
-
-impl Xform for ty::Variance {
- fn xform(self, v: ty::Variance) -> ty::Variance {
- // "Variance transformation", Figure 1 of The Paper
- match (self, v) {
- // Figure 1, column 1.
- (ty::Covariant, ty::Covariant) => ty::Covariant,
- (ty::Covariant, ty::Contravariant) => ty::Contravariant,
- (ty::Covariant, ty::Invariant) => ty::Invariant,
- (ty::Covariant, ty::Bivariant) => ty::Bivariant,
-
- // Figure 1, column 2.
- (ty::Contravariant, ty::Covariant) => ty::Contravariant,
- (ty::Contravariant, ty::Contravariant) => ty::Covariant,
- (ty::Contravariant, ty::Invariant) => ty::Invariant,
- (ty::Contravariant, ty::Bivariant) => ty::Bivariant,
-
- // Figure 1, column 3.
- (ty::Invariant, _) => ty::Invariant,
-
- // Figure 1, column 4.
- (ty::Bivariant, _) => ty::Bivariant,
- }
- }
-}
-
pub fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
// Greatest lower bound of the variance lattice as
// defined in The Paper:
/// type is a static guarantee that the underlying bytes contain no interior 0
/// bytes and the final byte is 0.
///
-/// A `CString` is created from either a byte slice or a byte vector. After
-/// being created, a `CString` predominately inherits all of its methods from
-/// the `Deref` implementation to `[c_char]`. Note that the underlying array
-/// is represented as an array of `c_char` as opposed to `u8`. A `u8` slice
-/// can be obtained with the `as_bytes` method. Slices produced from a `CString`
-/// do *not* contain the trailing nul terminator unless otherwise specified.
+/// A `CString` is created from either a byte slice or a byte vector. A `u8`
+/// slice can be obtained with the `as_bytes` method. Slices produced from a
+/// `CString` do *not* contain the trailing nul terminator unless otherwise
+/// specified.
///
/// # Examples
///
pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
+
pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
+pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800;
pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
}
/// Gets a detailed string description for the given error number.
-pub fn error_string(errnum: i32) -> String {
+pub fn error_string(mut errnum: i32) -> String {
// This value is calculated from the macro
// MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
let langId = 0x0800 as c::DWORD;
let mut buf = [0 as c::WCHAR; 2048];
unsafe {
- let res = c::FormatMessageW(c::FORMAT_MESSAGE_FROM_SYSTEM |
+ let mut module = ptr::null_mut();
+ let mut flags = 0;
+
+ // NTSTATUS errors may be encoded as HRESULT, which may returned from
+ // GetLastError. For more information about Windows error codes, see
+ // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx
+ if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
+ // format according to https://support.microsoft.com/en-us/help/259693
+ const NTDLL_DLL: &'static [u16] = &['N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _,
+ '.' as _, 'D' as _, 'L' as _, 'L' as _, 0];
+ module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());
+
+ if module != ptr::null_mut() {
+ errnum ^= c::FACILITY_NT_BIT as i32;
+ flags = c::FORMAT_MESSAGE_FROM_HMODULE;
+ }
+ }
+
+ let res = c::FormatMessageW(flags | c::FORMAT_MESSAGE_FROM_SYSTEM |
c::FORMAT_MESSAGE_IGNORE_INSERTS,
- ptr::null_mut(),
+ module,
errnum as c::DWORD,
langId,
buf.as_mut_ptr(),
pub fn exit(code: i32) -> ! {
unsafe { c::ExitProcess(code as c::UINT) }
}
+
+#[cfg(test)]
+mod tests {
+ use io::Error;
+ use sys::c;
+
+ // tests `error_string` above
+ #[test]
+ fn ntstatus_error() {
+ const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
+ assert!(!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
+ .to_string().contains("FormatMessageW() returned error"));
+ }
+}
/// configuration methods can be chained.
///
/// If the [`stack_size`] field is not specified, the stack size
- /// will be the `RUST_MIN_STACK` environment variable, if it is
- /// not specified either, a sensible default size will be set (2MB as
+ /// will be the `RUST_MIN_STACK` environment variable. If it is
+ /// not specified either, a sensible default will be set (2MB as
/// of the writting of this doc).
///
/// # Examples
use codemap::{CodeMap, FilePathMapping};
use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
use errors::registry::Registry;
-use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
+use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
use errors::emitter::Emitter;
-use errors::snippet::Style;
use std::rc::Rc;
use std::io::{self, Write};
fn from_diagnostic_builder(db: &DiagnosticBuilder,
je: &JsonEmitter)
-> Diagnostic {
- let sugg = db.suggestion.as_ref().map(|sugg| {
- SubDiagnostic {
- level: Level::Help,
- message: vec![(sugg.msg.clone(), Style::NoStyle)],
- span: MultiSpan::new(),
- render_span: Some(RenderSpan::Suggestion(sugg.clone())),
- }
+ let sugg = db.suggestions.iter().flat_map(|sugg| {
+ je.render(sugg).into_iter().map(move |rendered| {
+ Diagnostic {
+ message: sugg.msg.clone(),
+ code: None,
+ level: "help",
+ spans: DiagnosticSpan::from_suggestion(sugg, je),
+ children: vec![],
+ rendered: Some(rendered),
+ }
+ })
});
- let sugg = sugg.as_ref();
Diagnostic {
message: db.message(),
code: DiagnosticCode::map_opt_string(db.code.clone(), je),
level: db.level.to_str(),
spans: DiagnosticSpan::from_multispan(&db.span, je),
- children: db.children.iter().chain(sugg).map(|c| {
+ children: db.children.iter().map(|c| {
Diagnostic::from_sub_diagnostic(c, je)
- }).collect(),
+ }).chain(sugg).collect(),
rendered: None,
}
}
.map(|sp| DiagnosticSpan::from_render_span(sp, je))
.unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)),
children: vec![],
- rendered: db.render_span.as_ref()
- .and_then(|rsp| je.render(rsp)),
+ rendered: None,
}
}
}
fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter)
-> Vec<DiagnosticSpan> {
- assert_eq!(suggestion.msp.span_labels().len(), suggestion.substitutes.len());
- suggestion.msp.span_labels()
- .into_iter()
- .zip(&suggestion.substitutes)
- .map(|(span_label, suggestion)| {
- DiagnosticSpan::from_span_label(span_label,
- Some(suggestion),
- je)
+ suggestion.substitution_parts
+ .iter()
+ .flat_map(|substitution| {
+ substitution.substitutions.iter().map(move |suggestion| {
+ let span_label = SpanLabel {
+ span: substitution.span,
+ is_primary: true,
+ label: None,
+ };
+ DiagnosticSpan::from_span_label(span_label,
+ Some(suggestion),
+ je)
+ })
})
.collect()
}
match *rsp {
RenderSpan::FullSpan(ref msp) =>
DiagnosticSpan::from_multispan(msp, je),
- RenderSpan::Suggestion(ref suggestion) =>
- DiagnosticSpan::from_suggestion(suggestion, je),
+ // regular diagnostics don't produce this anymore
+ // FIXME(oli_obk): remove it entirely
+ RenderSpan::Suggestion(_) => unreachable!(),
}
}
}
}
impl JsonEmitter {
- fn render(&self, render_span: &RenderSpan) -> Option<String> {
- use std::borrow::Borrow;
-
- match *render_span {
- RenderSpan::FullSpan(_) => {
- None
- }
- RenderSpan::Suggestion(ref suggestion) => {
- Some(suggestion.splice_lines(self.cm.borrow()))
- }
- }
+ fn render(&self, suggestion: &CodeSuggestion) -> Vec<String> {
+ suggestion.splice_lines(&*self.cm)
}
}
+++ /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.
-
-// compile-flags:-C target-feature=+crt-static
-// error-pattern: specifying the `crt-static` target feature is only allowed
-
-fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-enum Fruit {
+// these two HELPs are actually in a new line between this line and the `enum Fruit` line
+enum Fruit { //~ HELP possible candidate is found in another module, you can import it into scope
+ //~^ HELP possible candidate is found in another module, you can import it into scope
Apple(i64),
//~^ HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`?
//~| HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`?
Apple(5)
//~^ ERROR cannot find function `Apple` in this scope
//~| NOTE not found in this scope
- //~| HELP possible candidate is found in another module, you can import it into scope
}
fn should_return_fruit_too() -> Fruit::Apple {
Apple(5)
//~^ ERROR cannot find function `Apple` in this scope
//~| NOTE not found in this scope
- //~| HELP possible candidate is found in another module, you can import it into scope
}
fn foo() -> Ok {
// over time, but this test used to exhibit some pretty bogus messages
// that were not remotely helpful.
-// error-pattern:cannot infer
-// error-pattern:cannot outlive the lifetime 'a
-// error-pattern:must be valid for the static lifetime
+// error-pattern:the lifetime 'a
+// error-pattern:the static lifetime
struct Invariant<'a>(Option<&'a mut &'a mut ()>);
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
// Without knowing 'a:'b, we can't coerce
- x //~ ERROR cannot infer an appropriate lifetime
+ x //~ ERROR lifetime bound not satisfied
//~^ ERROR cannot infer an appropriate lifetime
}
-> Box<Get<&'min i32>>
where 'max : 'min
{
- v //~ ERROR cannot infer an appropriate lifetime
+ v //~ ERROR mismatched types
}
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
where 'max : 'min
{
// Previously OK:
- v //~ ERROR cannot infer an appropriate lifetime
+ v //~ ERROR mismatched types
}
fn main() { }
where 'max : 'min
{
// Previously OK, now an error as traits are invariant.
- v //~ ERROR cannot infer an appropriate lifetime
+ v //~ ERROR mismatched types
}
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
-> Box<Get<&'max i32>>
where 'max : 'min
{
- v //~ ERROR cannot infer an appropriate lifetime
+ v //~ ERROR mismatched types
}
fn main() { }
-> Box<Get<&'min i32>>
where 'max : 'min
{
- v //~ ERROR cannot infer an appropriate lifetime
+ v //~ ERROR mismatched types
}
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
-> Box<Get<&'max i32>>
where 'max : 'min
{
- v //~ ERROR cannot infer an appropriate lifetime
+ v //~ ERROR mismatched types
}
fn main() { }
--- /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.
+
+// Regression test for #41677. The local variable was winding up with
+// a type `Receiver<?T, H>` where `?T` was unconstrained, because we
+// failed to enforce the WF obligations and `?T` is a bivariant type
+// parameter position.
+
+#![allow(unused_variables, dead_code)]
+
+use std::marker::PhantomData;
+
+trait Handle {
+ type Inner;
+}
+
+struct ResizingHandle<H>(PhantomData<H>);
+impl<H> Handle for ResizingHandle<H> {
+ type Inner = H;
+}
+
+struct Receiver<T, H: Handle<Inner=T>>(PhantomData<H>);
+
+fn channel<T>(size: usize) -> Receiver<T, ResizingHandle<T>> {
+ let rx = Receiver(PhantomData);
+ rx
+}
+
+fn main() {
+}
--- /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.
+
+// Regression test for #41849.
+
+use std::ops::Mul;
+
+const C: usize = 1;
+const CAPACITY: usize = 1 * C;
+
+struct A<X> {
+ f: [X; CAPACITY],
+}
+
+struct B<T> {
+ f: T,
+}
+
+impl<T> Mul for B<T> {
+ type Output = Self;
+ fn mul(self, _rhs: B<T>) -> Self::Output {
+ self
+ }
+}
+
+impl<T> Mul<usize> for B<T> {
+ type Output = Self;
+ fn mul(self, _rhs: usize) -> Self::Output {
+ self
+ }
+}
+
+fn main() {
+ let a = A { f: [1] };
+ let _ = B { f: a };
+}
15 | let _ = namespaced_enums::A;
| ^ not found in `namespaced_enums`
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use namespaced_enums::Foo::A;`
+help: possible candidate is found in another module, you can import it into scope
+ | use namespaced_enums::Foo::A;
error[E0425]: cannot find function `B` in module `namespaced_enums`
--> $DIR/enums-are-namespaced-xc.rs:18:31
18 | let _ = namespaced_enums::B(10);
| ^ not found in `namespaced_enums`
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use namespaced_enums::Foo::B;`
+help: possible candidate is found in another module, you can import it into scope
+ | use namespaced_enums::Foo::B;
error[E0422]: cannot find struct, variant or union type `C` in module `namespaced_enums`
--> $DIR/enums-are-namespaced-xc.rs:21:31
21 | let _ = namespaced_enums::C { a: 10 };
| ^ not found in `namespaced_enums`
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use namespaced_enums::Foo::C;`
+help: possible candidate is found in another module, you can import it into scope
+ | use namespaced_enums::Foo::C;
error: aborting due to 3 previous errors
19 | Result {
| ^^^^^^ not a struct, variant or union type
|
- = help: possible better candidates are found in other modules, you can import them into scope:
- `use std::fmt::Result;`
- `use std::io::Result;`
- `use std::thread::Result;`
+help: possible better candidates are found in other modules, you can import them into scope
+ | use std::fmt::Result;
+ | use std::io::Result;
+ | use std::thread::Result;
error: aborting due to previous error
16 | E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
| ^ not found in this scope
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use SomeEnum::E;`
+help: possible candidate is found in another module, you can import it into scope
+ | use SomeEnum::E;
error: aborting due to previous error
53 | impl Mul for Foo {
| ^^^ not found in this scope
|
- = help: possible candidates are found in other modules, you can import them into scope:
- `use mul1::Mul;`
- `use mul2::Mul;`
- `use std::ops::Mul;`
+help: possible candidates are found in other modules, you can import them into scope
+ | use mul1::Mul;
+ | use mul2::Mul;
+ | use std::ops::Mul;
error[E0412]: cannot find type `Mul` in this scope
--> $DIR/issue-21221-1.rs:72:16
72 | fn getMul() -> Mul {
| ^^^ not found in this scope
|
- = help: possible candidates are found in other modules, you can import them into scope:
- `use mul1::Mul;`
- `use mul2::Mul;`
- `use mul3::Mul;`
- `use mul4::Mul;`
- and 2 other candidates
+help: possible candidates are found in other modules, you can import them into scope
+ | use mul1::Mul;
+ | use mul2::Mul;
+ | use mul3::Mul;
+ | use mul4::Mul;
+and 2 other candidates
error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
--> $DIR/issue-21221-1.rs:83:6
88 | impl Div for Foo {
| ^^^ not found in this scope
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use std::ops::Div;`
+help: possible candidate is found in another module, you can import it into scope
+ | use std::ops::Div;
error: cannot continue compilation due to previous error
28 | impl T for Foo { }
| ^ not found in this scope
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use foo::bar::T;`
+help: possible candidate is found in another module, you can import it into scope
+ | use foo::bar::T;
error: main function not found
25 | impl OuterTrait for Foo {}
| ^^^^^^^^^^ not found in this scope
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use issue_21221_3::outer::OuterTrait;`
+help: possible candidate is found in another module, you can import it into scope
+ | use issue_21221_3::outer::OuterTrait;
error: cannot continue compilation due to previous error
20 | impl T for Foo {}
| ^ not found in this scope
|
- = help: possible candidate is found in another module, you can import it into scope:
- `use issue_21221_4::T;`
+help: possible candidate is found in another module, you can import it into scope
+ | use issue_21221_4::T;
error: cannot continue compilation due to previous error
20 | impl Foo for S { //~ ERROR expected trait, found type alias `Foo`
| ^^^ type aliases cannot be used for traits
|
- = help: possible better candidate is found in another module, you can import it into scope:
- `use issue_3907::Foo;`
+help: possible better candidate is found in another module, you can import it into scope
+ | use issue_3907::Foo;
error: cannot continue compilation due to previous error
| did you mean `S`?
| constructor is not visible here due to private fields
|
- = help: possible better candidate is found in another module, you can import it into scope:
- `use m::n::Z;`
+help: possible better candidate is found in another module, you can import it into scope
+ | use m::n::Z;
error[E0423]: expected value, found struct `S`
--> $DIR/privacy-struct-ctor.rs:36:5
| did you mean `S { /* fields */ }`?
| constructor is not visible here due to private fields
|
- = help: possible better candidate is found in another module, you can import it into scope:
- `use m::S;`
+help: possible better candidate is found in another module, you can import it into scope
+ | use m::S;
error[E0423]: expected value, found struct `xcrate::S`
--> $DIR/privacy-struct-ctor.rs:42:5
| did you mean `xcrate::S { /* fields */ }`?
| constructor is not visible here due to private fields
|
- = help: possible better candidate is found in another module, you can import it into scope:
- `use m::S;`
+help: possible better candidate is found in another module, you can import it into scope
+ | use m::S;
error: tuple struct `Z` is private
--> $DIR/privacy-struct-ctor.rs:25:9
15 | impl<T: Clone, Add> Add for Foo<T> {
| ^^^ not a trait
|
- = help: possible better candidate is found in another module, you can import it into scope:
- `use std::ops::Add;`
+help: possible better candidate is found in another module, you can import it into scope
+ | use std::ops::Add;
error: main function not found