From 119335efb1e1765896f2eaca6e89263455890647 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 16 Feb 2019 12:55:00 -0800 Subject: [PATCH 01/11] [BETA] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 9b5d4b755617d..f099fe94b66f0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 9b5d4b755617d60dd841912b354be8a6b6b3849a +Subproject commit f099fe94b66f0a2f80370be8f2d3db2a55b97050 From 94ca417f8a3a07bc17ab5657a90ce02f7dc3a9eb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 6 Feb 2019 11:57:11 +1100 Subject: [PATCH 02/11] Make `intern_lazy_const` actually intern its argument. Currently it just unconditionally allocates it in the arena. For a "Clean Check" build of the the `packed-simd` benchmark, this change reduces both the `max-rss` and `faults` counts by 59%; it slightly (~3%) increases the instruction counts but the `wall-time` is unchanged. For the same builds of a few other benchmarks, `max-rss` and `faults` drop by 1--5%, but instruction counts and `wall-time` changes are in the noise. Fixes #57432, fixes #57829. --- src/librustc/mir/mod.rs | 2 +- src/librustc/traits/project.rs | 4 ++-- src/librustc/traits/query/normalize.rs | 4 ++-- src/librustc/ty/codec.rs | 2 +- src/librustc/ty/context.rs | 22 ++++++++++--------- src/librustc/ty/structural_impls.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/build/misc.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 12 +++++----- src/librustc_mir/hair/cx/mod.rs | 6 ++--- src/librustc_mir/shim.rs | 6 ++--- src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustc_mir/transform/generator.rs | 4 ++-- src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- 17 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a1a6e890b1292..10015efa42232 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2154,7 +2154,7 @@ impl<'tcx> Operand<'tcx> { span, ty, user_ty: None, - literal: tcx.intern_lazy_const( + literal: tcx.mk_lazy_const( ty::LazyConst::Evaluated(ty::Const::zero_sized(ty)), ), }) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index bec45046cb93e..21151276e7299 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -408,7 +408,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { let substs = tcx.lift_to_global(&substs).unwrap(); let evaluated = evaluated.subst(tcx, substs); - return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); + return tcx.mk_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } else { @@ -420,7 +420,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, promoted: None }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); + return tcx.mk_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index be05445cfc61a..9f55bb95d259b 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -203,7 +203,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { let substs = tcx.lift_to_global(&substs).unwrap(); let evaluated = evaluated.subst(tcx, substs); - return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); + return tcx.mk_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } else { @@ -215,7 +215,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx promoted: None, }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); + return tcx.mk_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index e0e4d9c362a6c..a4a2471852739 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -252,7 +252,7 @@ pub fn decode_lazy_const<'a, 'tcx, D>(decoder: &mut D) where D: TyDecoder<'a, 'tcx>, 'tcx: 'a, { - Ok(decoder.tcx().intern_lazy_const(Decodable::decode(decoder)?)) + Ok(decoder.tcx().mk_lazy_const(Decodable::decode(decoder)?)) } #[inline] diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d69219efbd884..56c9a475bdb93 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -127,6 +127,7 @@ pub struct CtxtInterners<'tcx> { goal: InternedSet<'tcx, GoalKind<'tcx>>, goal_list: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>>, + lazy_const: InternedSet<'tcx, LazyConst<'tcx>>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { @@ -144,6 +145,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { goal: Default::default(), goal_list: Default::default(), projs: Default::default(), + lazy_const: Default::default(), } } @@ -1072,10 +1074,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.global_arenas.adt_def.alloc(def) } - pub fn intern_const_alloc( - self, - alloc: Allocation, - ) -> &'gcx Allocation { + pub fn intern_const_alloc(self, alloc: Allocation) -> &'gcx Allocation { self.allocation_interner.borrow_mut().intern(alloc, |alloc| { self.global_arenas.const_allocs.alloc(alloc) }) @@ -1095,10 +1094,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn intern_lazy_const(self, c: ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - self.global_interners.arena.alloc(c) - } - pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails { self.layout_interner.borrow_mut().intern(layout, |layout| { self.global_arenas.layout.alloc(layout) @@ -2238,6 +2233,12 @@ impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, GoalKind<'tcx>> } } +impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, LazyConst<'tcx>> { + fn borrow<'a>(&'a self) -> &'a LazyConst<'lcx> { + &self.0 + } +} + impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]> for Interned<'tcx, List>> { fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] { @@ -2344,7 +2345,8 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { direct_interners!('tcx, region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind, - goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx> + goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx>, + lazy_const: mk_lazy_const(|c: &LazyConst<'_>| keep_local(&c)) -> LazyConst<'tcx> ); macro_rules! slice_interners { @@ -2529,7 +2531,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(Array(ty, self.intern_lazy_const( + self.mk_ty(Array(ty, self.mk_lazy_const( ty::LazyConst::Evaluated(ty::Const::from_usize(self.global_tcx(), n)) ))) } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 258470bf6f860..dd9ffd08a4ef5 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1042,7 +1042,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::LazyConst<'tcx> { ty::LazyConst::Unevaluated(*def_id, substs.fold_with(folder)) } }; - folder.tcx().intern_lazy_const(new) + folder.tcx().mk_lazy_const(new) } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index e0fc90931696e..d408883c16c69 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -268,7 +268,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: expr_span, ty: this.hir.tcx().types.u32, user_ty: None, - literal: this.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated( + literal: this.hir.tcx().mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::from_bits( this.hir.tcx(), 0, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 696c173b048ad..6e836f7059b83 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -302,7 +302,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]); - let method = self.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(method)); + let method = self.hir.tcx().mk_lazy_const(ty::LazyConst::Evaluated(method)); let re_erased = self.hir.tcx().types.re_erased; // take the argument by reference diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index c849c02242840..a7b201fc0dbc6 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -33,7 +33,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span, ty, user_ty: None, - literal: self.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(literal)), + literal: self.hir.tcx().mk_lazy_const(ty::LazyConst::Evaluated(literal)), }; Operand::Constant(constant) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index eb536fbcf69bb..aa754888fcb31 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -342,7 +342,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Lit(ref lit) => ExprKind::Literal { - literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + literal: cx.tcx.mk_lazy_const(ty::LazyConst::Evaluated( cx.const_eval_literal(&lit.node, expr_ty, lit.span, false) )), user_ty: None, @@ -442,7 +442,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { if let hir::ExprKind::Lit(ref lit) = arg.node { ExprKind::Literal { - literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + literal: cx.tcx.mk_lazy_const(ty::LazyConst::Evaluated( cx.const_eval_literal(&lit.node, expr_ty, lit.span, true) )), user_ty: None, @@ -702,7 +702,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty: var_ty, span: expr.span, kind: ExprKind::Literal { - literal: cx.tcx.intern_lazy_const(literal), + literal: cx.tcx.mk_lazy_const(literal), user_ty: None }, }.to_ref(); @@ -856,7 +856,7 @@ fn method_callee<'a, 'gcx, 'tcx>( ty, span, kind: ExprKind::Literal { - literal: cx.tcx().intern_lazy_const(ty::LazyConst::Evaluated( + literal: cx.tcx().mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::zero_sized(ty) )), user_ty, @@ -918,7 +918,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); debug!("convert_path_expr: user_ty={:?}", user_ty); ExprKind::Literal { - literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::zero_sized( + literal: cx.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::zero_sized( cx.tables().node_id_to_type(expr.hir_id), ))), user_ty, @@ -930,7 +930,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { - literal: cx.tcx.intern_lazy_const(ty::LazyConst::Unevaluated(def_id, substs)), + literal: cx.tcx.mk_lazy_const(ty::LazyConst::Unevaluated(def_id, substs)), user_ty, } }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 6113d88e09591..ae0c493e77b8a 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::LazyConst<'tcx> { - self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_usize(self.tcx, value))) + self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_usize(self.tcx, value))) } pub fn bool_ty(&mut self) -> Ty<'tcx> { @@ -121,11 +121,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn true_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> { - self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, true))) + self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, true))) } pub fn false_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> { - self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, false))) + self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, false))) } pub fn const_eval_literal( diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 751815eab287b..15796186063de 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -459,7 +459,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: func_ty, user_ty: None, - literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated( + literal: tcx.mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::zero_sized(func_ty), )), }); @@ -521,7 +521,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: self.tcx.types.usize, user_ty: None, - literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + literal: self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::from_usize(self.tcx, value), )), } @@ -759,7 +759,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, ty, user_ty: None, - literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated( + literal: tcx.mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::zero_sized(ty) )), }), diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 06e16de8b43bc..9b75a70ff41d2 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -533,7 +533,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { span, ty: self.tcx.types.bool, user_ty: None, - literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + literal: self.tcx.mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::from_bool(self.tcx, val), )), }))) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index ec0c118634d0f..4b7e89130cd2c 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -171,7 +171,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { span: source_info.span, ty: self.tcx.types.u32, user_ty: None, - literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits( + literal: self.tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits( self.tcx, state_disc.into(), ty::ParamEnv::empty().and(self.tcx.types.u32) @@ -687,7 +687,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: mir.span, ty: tcx.types.bool, user_ty: None, - literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated( + literal: tcx.mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::from_bool(tcx, false), )), }), diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 8b55a4424ae29..eedc42927c126 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -963,7 +963,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> span: self.source_info.span, ty: self.tcx().types.usize, user_ty: None, - literal: self.tcx().intern_lazy_const(ty::LazyConst::Evaluated( + literal: self.tcx().mk_lazy_const(ty::LazyConst::Evaluated( ty::Const::from_usize(self.tcx(), val.into()) )), }) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 8e5eaa18b9de0..b4d44168a05f8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1779,7 +1779,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let length_def_id = tcx.hir().local_def_id(length.id); let substs = Substs::identity_for_item(tcx, length_def_id); let length = ty::LazyConst::Unevaluated(length_def_id, substs); - let length = tcx.intern_lazy_const(length); + let length = tcx.mk_lazy_const(length); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1b07385d4d1f4..5163ae9b7747c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4592,7 +4592,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if element_ty.references_error() { tcx.types.err } else if let Ok(count) = count { - tcx.mk_ty(ty::Array(t, tcx.intern_lazy_const(ty::LazyConst::Evaluated(count)))) + tcx.mk_ty(ty::Array(t, tcx.mk_lazy_const(ty::LazyConst::Evaluated(count)))) } else { tcx.types.err } From 04d6d7b974ba2bf573e31cce1b3176baa69d554a Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 4 Feb 2019 19:12:46 +0100 Subject: [PATCH 03/11] Lower constant patterns with ascribed types. This commit fixes a bug introduced by #55937 which started checking user type annotations for associated type patterns. Where lowering a associated constant expression would previously return a `PatternKind::Constant`, it now returns a `PatternKind::AscribeUserType` with a `PatternKind::Constant` inside, this commit unwraps that to access the constant pattern inside and behaves as before. --- src/librustc_mir/hair/pattern/mod.rs | 33 ++++++++++++++++++++--- src/test/ui/nll/issue-57960.rs | 39 ++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/nll/issue-57960.rs diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 8991a90737c7e..680831782a01f 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -164,6 +164,17 @@ pub enum PatternKind<'tcx> { }, } +impl<'tcx> PatternKind<'tcx> { + /// If this is a `PatternKind::AscribeUserType` then return the subpattern kind, otherwise + /// return this pattern kind. + fn with_user_type_ascription_subpattern(self) -> Self { + match self { + PatternKind::AscribeUserType { subpattern: Pattern { box kind, .. }, .. } => kind, + kind => kind, + } + } +} + #[derive(Clone, Copy, Debug, PartialEq)] pub struct PatternRange<'tcx> { pub lo: ty::Const<'tcx>, @@ -400,9 +411,15 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatKind::Lit(ref value) => self.lower_lit(value), PatKind::Range(ref lo_expr, ref hi_expr, end) => { - match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) { - (PatternKind::Constant { value: lo }, - PatternKind::Constant { value: hi }) => { + match ( + // Look for `PatternKind::Constant` patterns inside of any + // `PatternKind::AscribeUserType` patterns. Type ascriptions can be safely + // ignored for the purposes of lowering a range correctly - these are checked + // elsewhere for well-formedness. + self.lower_lit(lo_expr).with_user_type_ascription_subpattern(), + self.lower_lit(hi_expr).with_user_type_ascription_subpattern(), + ) { + (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { use std::cmp::Ordering; let cmp = compare_const_vals( self.tcx, @@ -451,7 +468,15 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } } - _ => PatternKind::Wild + ref pats => { + self.tcx.sess.delay_span_bug( + pat.span, + &format!("found bad range pattern `{:?}` outside of error recovery", + pats), + ); + + PatternKind::Wild + } } } diff --git a/src/test/ui/nll/issue-57960.rs b/src/test/ui/nll/issue-57960.rs new file mode 100644 index 0000000000000..0b52e46c45989 --- /dev/null +++ b/src/test/ui/nll/issue-57960.rs @@ -0,0 +1,39 @@ +// run-pass + +#![allow(dead_code)] + +trait Range { + const FIRST: u8; + const LAST: u8; +} + +struct OneDigit; +impl Range for OneDigit { + const FIRST: u8 = 0; + const LAST: u8 = 9; +} + +struct TwoDigits; +impl Range for TwoDigits { + const FIRST: u8 = 10; + const LAST: u8 = 99; +} + +struct ThreeDigits; +impl Range for ThreeDigits { + const FIRST: u8 = 100; + const LAST: u8 = 255; +} + +fn digits(x: u8) -> u32 { + match x { + OneDigit::FIRST...OneDigit::LAST => 1, + TwoDigits::FIRST...TwoDigits::LAST => 2, + ThreeDigits::FIRST...ThreeDigits::LAST => 3, + _ => unreachable!(), + } +} + +fn main() { + assert_eq!(digits(100), 3); +} From 8a1b7da0cf8f5a5bd3a37e545e20159d339d046c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Mockers?= Date: Tue, 18 Dec 2018 02:22:08 +0100 Subject: [PATCH 04/11] #56411 do not suggest a fix for a import conflict in a macro --- src/librustc_resolve/lib.rs | 4 +++- src/test/ui/issues/issue-56411.rs | 17 +++++++++++++++ src/test/ui/issues/issue-56411.stderr | 31 +++++++++++++++++++++++++++ src/test/ui/issues/issue_56411.rs | 5 +++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-56411.rs create mode 100644 src/test/ui/issues/issue-56411.stderr create mode 100644 src/test/ui/issues/issue_56411.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a25009ccfb49c..ea50d8e18a0e7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -5103,11 +5103,13 @@ impl<'a> Resolver<'a> { if let ( Ok(snippet), NameBindingKind::Import { directive, ..}, - _dummy @ false, + false, + false, ) = ( cm.span_to_snippet(binding.span), binding.kind.clone(), binding.span.is_dummy(), + binding.span.ctxt().outer().expn_info().is_some(), ) { let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { format!("Other{}", name) diff --git a/src/test/ui/issues/issue-56411.rs b/src/test/ui/issues/issue-56411.rs new file mode 100644 index 0000000000000..599f277123cc8 --- /dev/null +++ b/src/test/ui/issues/issue-56411.rs @@ -0,0 +1,17 @@ +macro_rules! import { + ( $($name:ident),* ) => { + $( + mod $name; + pub use self::$name; + //~^ ERROR the name `issue_56411` is defined multiple times + //~| ERROR `issue_56411` is private, and cannot be re-exported + + )* + } +} + +import!(issue_56411); + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/issues/issue-56411.stderr b/src/test/ui/issues/issue-56411.stderr new file mode 100644 index 0000000000000..842d86f4a3a9c --- /dev/null +++ b/src/test/ui/issues/issue-56411.stderr @@ -0,0 +1,31 @@ +error[E0255]: the name `issue_56411` is defined multiple times + --> $DIR/issue-56411.rs:5:21 + | +LL | mod $name; + | ---------- previous definition of the module `issue_56411` here +LL | pub use self::$name; + | ^^^^^^^^^^^ + | | + | `issue_56411` reimported here + | you can use `as` to change the binding name of the import +... +LL | import!(issue_56411); + | --------------------- in this macro invocation + | + = note: `issue_56411` must be defined only once in the type namespace of this module + +error[E0365]: `issue_56411` is private, and cannot be re-exported + --> $DIR/issue-56411.rs:5:21 + | +LL | pub use self::$name; + | ^^^^^^^^^^^ re-export of private `issue_56411` +... +LL | import!(issue_56411); + | --------------------- in this macro invocation + | + = note: consider declaring type or module `issue_56411` with `pub` + +error: aborting due to 2 previous errors + +Some errors occurred: E0255, E0365. +For more information about an error, try `rustc --explain E0255`. diff --git a/src/test/ui/issues/issue_56411.rs b/src/test/ui/issues/issue_56411.rs new file mode 100644 index 0000000000000..bd689e913aba6 --- /dev/null +++ b/src/test/ui/issues/issue_56411.rs @@ -0,0 +1,5 @@ +// compile-pass + +struct T {} + +fn main() {} From e4120ee67864524c503ee2f59b357ce93a43980b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 26 Jan 2019 00:36:50 +0300 Subject: [PATCH 05/11] Address review comments and cleanup code --- src/librustc_resolve/lib.rs | 93 +++++++++---------- src/test/ui/issues/issue-56411.rs | 6 +- src/test/ui/issues/issue-56411.stderr | 22 ++--- .../{issue_56411.rs => issue_56411_aux.rs} | 0 4 files changed, 59 insertions(+), 62 deletions(-) rename src/test/ui/issues/{issue_56411.rs => issue_56411_aux.rs} (100%) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ea50d8e18a0e7..c231e71e582cb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -5090,62 +5090,59 @@ impl<'a> Resolver<'a> { } // See https://github.com/rust-lang/rust/issues/32354 - if old_binding.is_import() || new_binding.is_import() { - let binding = if new_binding.is_import() && !new_binding.span.is_dummy() { - new_binding + let directive = match (&new_binding.kind, &old_binding.kind) { + (NameBindingKind::Import { directive, .. }, _) if !new_binding.span.is_dummy() => + Some((directive, new_binding.span)), + (_, NameBindingKind::Import { directive, .. }) if !old_binding.span.is_dummy() => + Some((directive, old_binding.span)), + _ => None, + }; + if let Some((directive, binding_span)) = directive { + let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { + format!("Other{}", name) } else { - old_binding + format!("other_{}", name) }; - let cm = self.session.source_map(); - let rename_msg = "you can use `as` to change the binding name of the import"; - - if let ( - Ok(snippet), - NameBindingKind::Import { directive, ..}, - false, - false, - ) = ( - cm.span_to_snippet(binding.span), - binding.kind.clone(), - binding.span.is_dummy(), - binding.span.ctxt().outer().expn_info().is_some(), - ) { - let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { - format!("Other{}", name) - } else { - format!("other_{}", name) - }; + let mut suggestion = None; + match directive.subclass { + ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } => + suggestion = Some(format!("self as {}", suggested_name)), + ImportDirectiveSubclass::SingleImport { source, .. } => { + if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0) + .map(|pos| pos as usize) { + if let Ok(snippet) = self.session.source_map() + .span_to_snippet(binding_span) { + if pos <= snippet.len() { + suggestion = Some(format!( + "{} as {}{}", + &snippet[..pos], + suggested_name, + if snippet.ends_with(";") { ";" } else { "" } + )) + } + } + } + } + ImportDirectiveSubclass::ExternCrate { source, target, .. } => + suggestion = Some(format!( + "extern crate {} as {};", + source.unwrap_or(target.name), + suggested_name, + )), + _ => unreachable!(), + } + let rename_msg = "you can use `as` to change the binding name of the import"; + if let Some(suggestion) = suggestion { err.span_suggestion_with_applicability( - binding.span, - &rename_msg, - match directive.subclass { - ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } => - format!("self as {}", suggested_name), - ImportDirectiveSubclass::SingleImport { source, .. } => - format!( - "{} as {}{}", - &snippet[..((source.span.hi().0 - binding.span.lo().0) as usize)], - suggested_name, - if snippet.ends_with(";") { - ";" - } else { - "" - } - ), - ImportDirectiveSubclass::ExternCrate { source, target, .. } => - format!( - "extern crate {} as {};", - source.unwrap_or(target.name), - suggested_name, - ), - _ => unreachable!(), - }, + binding_span, + rename_msg, + suggestion, Applicability::MaybeIncorrect, ); } else { - err.span_label(binding.span, rename_msg); + err.span_label(binding_span, rename_msg); } } diff --git a/src/test/ui/issues/issue-56411.rs b/src/test/ui/issues/issue-56411.rs index 599f277123cc8..3561c21cc7ee3 100644 --- a/src/test/ui/issues/issue-56411.rs +++ b/src/test/ui/issues/issue-56411.rs @@ -3,14 +3,14 @@ macro_rules! import { $( mod $name; pub use self::$name; - //~^ ERROR the name `issue_56411` is defined multiple times - //~| ERROR `issue_56411` is private, and cannot be re-exported + //~^ ERROR the name `issue_56411_aux` is defined multiple times + //~| ERROR `issue_56411_aux` is private, and cannot be re-exported )* } } -import!(issue_56411); +import!(issue_56411_aux); fn main() { println!("Hello, world!"); diff --git a/src/test/ui/issues/issue-56411.stderr b/src/test/ui/issues/issue-56411.stderr index 842d86f4a3a9c..dd05852c09159 100644 --- a/src/test/ui/issues/issue-56411.stderr +++ b/src/test/ui/issues/issue-56411.stderr @@ -1,29 +1,29 @@ -error[E0255]: the name `issue_56411` is defined multiple times +error[E0255]: the name `issue_56411_aux` is defined multiple times --> $DIR/issue-56411.rs:5:21 | LL | mod $name; - | ---------- previous definition of the module `issue_56411` here + | ---------- previous definition of the module `issue_56411_aux` here LL | pub use self::$name; | ^^^^^^^^^^^ | | - | `issue_56411` reimported here + | `issue_56411_aux` reimported here | you can use `as` to change the binding name of the import ... -LL | import!(issue_56411); - | --------------------- in this macro invocation +LL | import!(issue_56411_aux); + | ------------------------- in this macro invocation | - = note: `issue_56411` must be defined only once in the type namespace of this module + = note: `issue_56411_aux` must be defined only once in the type namespace of this module -error[E0365]: `issue_56411` is private, and cannot be re-exported +error[E0365]: `issue_56411_aux` is private, and cannot be re-exported --> $DIR/issue-56411.rs:5:21 | LL | pub use self::$name; - | ^^^^^^^^^^^ re-export of private `issue_56411` + | ^^^^^^^^^^^ re-export of private `issue_56411_aux` ... -LL | import!(issue_56411); - | --------------------- in this macro invocation +LL | import!(issue_56411_aux); + | ------------------------- in this macro invocation | - = note: consider declaring type or module `issue_56411` with `pub` + = note: consider declaring type or module `issue_56411_aux` with `pub` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue_56411.rs b/src/test/ui/issues/issue_56411_aux.rs similarity index 100% rename from src/test/ui/issues/issue_56411.rs rename to src/test/ui/issues/issue_56411_aux.rs From 5f39bc716c0cad7dafe64ecc4311fd7bdbbb09cd Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 22 Jan 2019 13:51:30 +0100 Subject: [PATCH 06/11] Do not initiate nested probe within `assemble_probe`. In particular, the table entries (associated with type-variables created during the probe) must persist as long as the candidates assembled during the probe. If you make a nested probe without creating a nested `ProbeContext`, the table entries are popped at the end of the nested probe, while the type-variables would leak out via the assembled candidates attached to `self` (the outer `ProbeContext`). This causes an ICE (*if you are lucky*)! --- src/librustc_typeck/check/method/probe.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9a828ce01775c..b849be52a9223 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -506,15 +506,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { match self_ty.value.value.sty { ty::Dynamic(ref data, ..) => { if let Some(p) = data.principal() { - self.fcx.probe(|_| { - let InferOk { value: self_ty, obligations: _ } = - self.fcx.probe_instantiate_query_response( - self.span, &self.orig_steps_var_values, self_ty) - .unwrap_or_else(|_| { - span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty) - }); - self.assemble_inherent_candidates_from_object(self_ty); - }); + let InferOk { value: instantiated_self_ty, obligations: _ } = + self.fcx.probe_instantiate_query_response( + self.span, &self.orig_steps_var_values, self_ty) + .unwrap_or_else(|_| { + span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty) + }); + self.assemble_inherent_candidates_from_object(instantiated_self_ty); self.assemble_inherent_impl_candidates_for_type(p.def_id()); } } From d820e217e501c10389a35f35bd47f777b2fa3511 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 22 Jan 2019 14:49:18 +0100 Subject: [PATCH 07/11] unit test for issue 57673. --- .../issue-57673-ice-on-deref-of-boxed-trait.rs | 7 +++++++ .../issue-57673-ice-on-deref-of-boxed-trait.stderr | 14 ++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs create mode 100644 src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr diff --git a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs new file mode 100644 index 0000000000000..0a4e7da2bff50 --- /dev/null +++ b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs @@ -0,0 +1,7 @@ +//extern crate has_assoc_type; + +//fn ice(x: Box>) { +fn ice(x: Box>) { + *x //~ ERROR mismatched types [E0308] +} +fn main() {} diff --git a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr new file mode 100644 index 0000000000000..bb63917fc0860 --- /dev/null +++ b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-57673-ice-on-deref-of-boxed-trait.rs:5:5 + | +LL | fn ice(x: Box>) { + | - possibly return type missing here? +LL | *x //~ ERROR mismatched types [E0308] + | ^^ expected (), found trait std::iter::Iterator + | + = note: expected type `()` + found type `(dyn std::iter::Iterator + 'static)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From d30f5bef0d5da8cdb5de23b83ded616e1dc28dfb Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 29 Jan 2019 00:59:13 +0200 Subject: [PATCH 08/11] add some comments to method::probe::Candidate --- src/librustc_typeck/check/method/probe.rs | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b849be52a9223..03a0f6233a75e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -85,6 +85,37 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { #[derive(Debug)] struct Candidate<'tcx> { + // Candidates are (I'm not quite sure, but they are mostly) basically + // some metadata on top of a `ty::AssociatedItem` (without substs). + // + // However, method probing wants to be able to evaluate the predicates + // for a function with the substs applied - for example, if a function + // has `where Self: Sized`, we don't want to consider it unless `Self` + // is actually `Sized`, and similarly, return-type suggestions want + // to consider the "actual" return type. + // + // The way this is handled is through `xform_self_ty`. It contains + // the receiver type of this candidate, but `xform_self_ty`, + // `xform_ret_ty` and `kind` (which contains the predicates) have the + // generic parameters of this candidate substituted with the *same set* + // of inference variables, which acts as some weird sort of "query". + // + // When we check out a candidate, we require `xform_self_ty` to be + // a subtype of the passed-in self-type, and this equates the type + // variables in the rest of the fields. + // + // For example, if we have this candidate: + // ``` + // trait Foo { + // fn foo(&self) where Self: Sized; + // } + // ``` + // + // Then `xform_self_ty` will be `&'erased ?X` and `kind` will contain + // the predicate `?X: Sized`, so if we are evaluating `Foo` for a + // the receiver `&T`, we'll do the subtyping which will make `?X` + // get the right value, then when we evaluate the predicate we'll check + // if `T: Sized`. xform_self_ty: Ty<'tcx>, xform_ret_ty: Option>, item: ty::AssociatedItem, From 552e2fa4e5c74a1323c0c5fd0b59912f6f727820 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 29 Jan 2019 00:59:30 +0200 Subject: [PATCH 09/11] add tests to a few edge cases in method lookup These aren't fixed by this PR, but were broken in a few older attempts at it. Make sure they don't regress. --- ...-same-trait-object-with-separate-params.rs | 177 ++++++++++++++++++ ...e-trait-object-with-separate-params.stderr | 72 +++++++ .../methods/method-trait-object-with-hrtb.rs | 41 ++++ 3 files changed, 290 insertions(+) create mode 100644 src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs create mode 100644 src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr create mode 100644 src/test/ui/methods/method-trait-object-with-hrtb.rs diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs new file mode 100644 index 0000000000000..a5dae1c71cdaa --- /dev/null +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs @@ -0,0 +1,177 @@ +#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals)] + +// This tests a few edge-cases around `arbitrary_self_types`. Most specifically, +// it checks that the `ObjectCandidate` you get from method matching can't +// match a trait with the same DefId as a supertrait but a bad type parameter. + +use std::marker::PhantomData; + +mod internal { + use std::ops::{CoerceUnsized, Deref, DispatchFromDyn}; + use std::marker::{PhantomData, Unsize}; + + pub struct Smaht(pub Box, pub PhantomData); + + impl Deref for Smaht { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl, U: ?Sized, MISC> CoerceUnsized> + for Smaht + {} + impl, U: ?Sized, MISC> DispatchFromDyn> + for Smaht + {} + + pub trait Foo: X {} + pub trait X { + fn foo(self: Smaht) -> T; + } + + impl X for () { + fn foo(self: Smaht) -> u32 { + 0 + } + } + + pub trait Marker {} + impl Marker for dyn Foo {} + impl X for T { + fn foo(self: Smaht) -> u64 { + 1 + } + } + + impl Deref for dyn Foo { + type Target = (); + fn deref(&self) -> &() { &() } + } + + impl Foo for () {} +} + +pub trait FinalFoo { + fn foo(&self) -> u8; +} + +impl FinalFoo for () { + fn foo(&self) -> u8 { 0 } +} + +mod nuisance_foo { + pub trait NuisanceFoo { + fn foo(self); + } + + impl NuisanceFoo for T { + fn foo(self) {} + } +} + + +fn objectcandidate_impl() { + let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht = x; + + // This picks `>::foo` via `ObjectCandidate`. + // + // The `TraitCandidate` is not relevant because `X` is not in scope. + let z = x.foo(); + + // Observe the type of `z` is `u32` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected (), found u32 +} + +fn traitcandidate_impl() { + use internal::X; + + let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht = x; + + // This picks `>::foo` via `TraitCandidate`. + // + // The `ObjectCandidate` does not apply, as it only applies to + // `X` (and not `X`). + let z = x.foo(); + + // Observe the type of `z` is `u64` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected (), found u64 +} + +fn traitcandidate_impl_with_nuisance() { + use internal::X; + use nuisance_foo::NuisanceFoo; + + let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht = x; + + // This picks `>::foo` via `TraitCandidate`. + // + // The `ObjectCandidate` does not apply, as it only applies to + // `X` (and not `X`). + // + // The NuisanceFoo impl has the same priority as the `X` impl, + // so we get a conflict. + let z = x.foo(); //~ ERROR multiple applicable items in scope +} + + +fn neither_impl() { + let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht = x; + + // This can't pick the `TraitCandidate` impl, because `Foo` is not + // imported. However, this also can't pick the `ObjectCandidate` + // impl, because it only applies to `X` (and not `X`). + // + // Therefore, neither of the candidates is applicable, and we pick + // the `FinalFoo` impl after another deref, which will return `u8`. + let z = x.foo(); + + // Observe the type of `z` is `u8` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected (), found u8 +} + +fn both_impls() { + use internal::X; + + let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht = x; + + // This can pick both the `TraitCandidate` and the `ObjectCandidate` impl. + // + // However, the `ObjectCandidate` is considered an "inherent candidate", + // and therefore has priority over both the `TraitCandidate` as well as + // any other "nuisance" candidate" (if present). + let z = x.foo(); + + // Observe the type of `z` is `u32` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected (), found u32 +} + + +fn both_impls_with_nuisance() { + // Similar to the `both_impls` example, except with a nuisance impl to + // make sure the `ObjectCandidate` indeed has a higher priority. + + use internal::X; + use nuisance_foo::NuisanceFoo; + + let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht = x; + let z = x.foo(); + + // Observe the type of `z` is `u32` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected (), found u32 +} + +fn main() { +} diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr new file mode 100644 index 0000000000000..2d8449b96de41 --- /dev/null +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -0,0 +1,72 @@ +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:85:24 + | +LL | let _seetype: () = z; //~ ERROR mismatched types + | ^ expected (), found u32 + | + = note: expected type `()` + found type `u32` + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:102:24 + | +LL | let _seetype: () = z; //~ ERROR mismatched types + | ^ expected (), found u64 + | + = note: expected type `()` + found type `u64` + +error[E0034]: multiple applicable items in scope + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:120:15 + | +LL | let z = x.foo(); //~ ERROR multiple applicable items in scope + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `internal::X` for the type `_` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:43:9 + | +LL | fn foo(self: Smaht) -> u64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 + | +LL | fn foo(self) {} + | ^^^^^^^^^^^^ +note: candidate #3 is defined in the trait `FinalFoo` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5 + | +LL | fn foo(&self) -> u8; + | ^^^^^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `FinalFoo::foo(x)` instead + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24 + | +LL | let _seetype: () = z; //~ ERROR mismatched types + | ^ expected (), found u8 + | + = note: expected type `()` + found type `u8` + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:155:24 + | +LL | let _seetype: () = z; //~ ERROR mismatched types + | ^ expected (), found u32 + | + = note: expected type `()` + found type `u32` + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:172:24 + | +LL | let _seetype: () = z; //~ ERROR mismatched types + | ^ expected (), found u32 + | + = note: expected type `()` + found type `u32` + +error: aborting due to 6 previous errors + +Some errors occurred: E0034, E0308. +For more information about an error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-trait-object-with-hrtb.rs b/src/test/ui/methods/method-trait-object-with-hrtb.rs new file mode 100644 index 0000000000000..da2f13f5a2f8a --- /dev/null +++ b/src/test/ui/methods/method-trait-object-with-hrtb.rs @@ -0,0 +1,41 @@ +// compile-pass + +// Check that method probing ObjectCandidate works in the presence of +// auto traits and/or HRTBs. + +mod internal { + pub trait MyObject<'a> { + type Output; + + fn foo(&self) -> Self::Output; + } + + impl<'a> MyObject<'a> for () { + type Output = &'a u32; + + fn foo(&self) -> Self::Output { &4 } + } +} + +fn t1(d: &dyn for<'a> internal::MyObject<'a, Output=&'a u32>) { + d.foo(); +} + +fn t2(d: &dyn internal::MyObject<'static, Output=&'static u32>) { + d.foo(); +} + +fn t3(d: &(dyn for<'a> internal::MyObject<'a, Output=&'a u32> + Sync)) { + d.foo(); +} + +fn t4(d: &(dyn internal::MyObject<'static, Output=&'static u32> + Sync)) { + d.foo(); +} + +fn main() { + t1(&()); + t2(&()); + t3(&()); + t4(&()); +} From 062e817ab2c129c07b70c183686e8fa1ef2c9b06 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 29 Jan 2019 01:00:42 +0200 Subject: [PATCH 10/11] avoid committing to autoderef in object method probing --- src/librustc_typeck/check/method/probe.rs | 29 ++++++--- .../method-probe-no-guessing-dyn-trait.rs | 59 +++++++++++++++++++ 2 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/methods/method-probe-no-guessing-dyn-trait.rs diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 03a0f6233a75e..be6a2ffa3eb7f 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -537,13 +537,28 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { match self_ty.value.value.sty { ty::Dynamic(ref data, ..) => { if let Some(p) = data.principal() { - let InferOk { value: instantiated_self_ty, obligations: _ } = - self.fcx.probe_instantiate_query_response( - self.span, &self.orig_steps_var_values, self_ty) - .unwrap_or_else(|_| { - span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty) - }); - self.assemble_inherent_candidates_from_object(instantiated_self_ty); + // Subtle: we can't use `instantiate_query_response` here: using it will + // commit to all of the type equalities assumed by inference going through + // autoderef (see the `method-probe-no-guessing` test). + // + // However, in this code, it is OK if we end up with an object type that is + // "more general" than the object type that we are evaluating. For *every* + // object type `MY_OBJECT`, a function call that goes through a trait-ref + // of the form `::func` is a valid + // `ObjectCandidate`, and it should be discoverable "exactly" through one + // of the iterations in the autoderef loop, so there is no problem with it + // being discoverable in another one of these iterations. + // + // Using `instantiate_canonical_with_fresh_inference_vars` on our + // `Canonical>>` and then *throwing away* the + // `CanonicalVarValues` will exactly give us such a generalization - it + // will still match the original object type, but it won't pollute our + // type variables in any form, so just do that! + let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = + self.fcx.instantiate_canonical_with_fresh_inference_vars( + self.span, &self_ty); + + self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_impl_candidates_for_type(p.def_id()); } } diff --git a/src/test/run-pass/methods/method-probe-no-guessing-dyn-trait.rs b/src/test/run-pass/methods/method-probe-no-guessing-dyn-trait.rs new file mode 100644 index 0000000000000..8c8165a100449 --- /dev/null +++ b/src/test/run-pass/methods/method-probe-no-guessing-dyn-trait.rs @@ -0,0 +1,59 @@ +// Check that method matching does not make "guesses" depending on +// Deref impls that don't eventually end up being picked. + +use std::ops::Deref; + +// An impl with less derefs will get called over an impl with more derefs, +// so `(t: Foo<_>).my_fn()` will use ` as MyTrait1>::my_fn(t)`, +// and does *not* force the `_` to equal `()`, because the Deref impl +// was *not* used. + +trait MyTrait1 { + fn my_fn(&self) {} +} + +impl MyTrait1 for Foo {} + +struct Foo(T); + +impl Deref for Foo<()> { + type Target = dyn MyTrait1 + 'static; + fn deref(&self) -> &(dyn MyTrait1 + 'static) { + panic!() + } +} + +// ...but if there is no impl with less derefs, the "guess" will be +// forced, so `(t: Bar<_>).my_fn2()` is `::my_fn2(*t)`, +// and because the deref impl is used, the `_` is forced to equal `u8`. + +trait MyTrait2 { + fn my_fn2(&self) {} +} + +impl MyTrait2 for u32 {} +struct Bar(T, u32); +impl Deref for Bar { + type Target = dyn MyTrait2 + 'static; + fn deref(&self) -> &(dyn MyTrait2 + 'static) { + &self.1 + } +} + +// actually invoke things + +fn main() { + let mut foo: Option> = None; + let mut bar: Option> = None; + let mut first_iter = true; + loop { + if !first_iter { + foo.as_ref().unwrap().my_fn(); + bar.as_ref().unwrap().my_fn2(); + break; + } + foo = Some(Foo(0)); + bar = Some(Bar(Default::default(), 0)); + first_iter = false; + } +} From e583c6244d09358ec1c143b90e6da3212d605faa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Jan 2019 23:21:10 +0100 Subject: [PATCH 11/11] Fixes text becoming invisible when element targetted --- src/librustdoc/html/static/themes/dark.css | 8 +------- src/librustdoc/html/static/themes/light.css | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 1390be700634d..52a30967a2310 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -82,12 +82,6 @@ pre { border-bottom-color: #ddd; } -:target { background: #494a3d; } - -:target > .in-band { - background: #494a3d; -} - .content .method .where, .content .fn .where, .content .where.fmt-newline { @@ -252,7 +246,7 @@ a.test-arrow:hover{ color: #999; } -:target > code { +:target > code, :target > .in-band { background-color: #494a3d; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 2b04dd2388d45..d20fea666e61d 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -84,12 +84,6 @@ pre { border-bottom-color: #ddd; } -:target { background: #FDFFD3; } - -:target > .in-band { - background: #FDFFD3; -} - .content .method .where, .content .fn .where, .content .where.fmt-newline { @@ -247,7 +241,7 @@ a.test-arrow:hover{ color: #999; } -:target > code { +:target > code, :target > .in-band { background: #FDFFD3; }