From 6a95d90b86fcfb04377db34324b513f108e4f060 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 14 Apr 2015 21:09:59 +0300 Subject: [PATCH 1/4] make Repr of TraitRef more useful --- src/librustc/util/ppaux.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 7358b4cc0f6..698f6c47502 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -810,8 +810,12 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { // to enumerate the `for<...>` etc because the debruijn index // tells you everything you need to know. let base = ty::item_path_str(tcx, self.def_id); - parameterized(tcx, &base, self.substs, self.def_id, &[], - || ty::lookup_trait_def(tcx, self.def_id).generics.clone()) + let result = parameterized(tcx, &base, self.substs, self.def_id, &[], + || ty::lookup_trait_def(tcx, self.def_id).generics.clone()); + match self.substs.self_ty() { + None => result, + Some(sty) => format!("<{} as {}>", sty.repr(tcx), result) + } } } @@ -1504,8 +1508,7 @@ impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> { impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("<{} as {}>::{}", - self.trait_ref.substs.self_ty().repr(tcx), + format!("{}::{}", self.trait_ref.repr(tcx), self.item_name.repr(tcx)) } From 9e1a07883bcf7b5881dec9bd1ff83ffd6da13d02 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 14 Apr 2015 21:14:42 +0300 Subject: [PATCH 2/4] clean visit_expr --- src/librustc_typeck/check/writeback.rs | 61 +++++++++++++------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f778a64f949..5eab90764d4 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -85,6 +85,32 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn tcx(&self) -> &'cx ty::ctxt<'tcx> { self.fcx.tcx() } + + // Hacky hack: During type-checking, we treat *all* operators + // as potentially overloaded. But then, during writeback, if + // we observe that something like `a+b` is (known to be) + // operating on scalars, we clear the overload. + fn fix_scalar_binary_expr(&mut self, e: &ast::Expr) { + if let ast::ExprBinary(ref op, ref lhs, ref rhs) = e.node { + let lhs_ty = self.fcx.expr_ty(lhs.id); + let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty); + + let rhs_ty = self.fcx.expr_ty(rhs.id); + let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty); + + if ty::type_is_scalar(lhs_ty) && ty::type_is_scalar(rhs_ty) { + self.fcx.inh.method_map.borrow_mut().remove(&MethodCall::expr(e.id)); + + // weird but true: the by-ref binops put an + // adjustment on the lhs but not the rhs; the + // adjustment for rhs is kind of baked into the + // system. + if !ast_util::is_by_value_binop(op.node) { + self.fcx.inh.adjustments.borrow_mut().remove(&lhs.id); + } + } + } + } } /////////////////////////////////////////////////////////////////////////// @@ -114,43 +140,16 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { return; } - // Hacky hack: During type-checking, we treat *all* operators - // as potentially overloaded. But then, during writeback, if - // we observe that something like `a+b` is (known to be) - // operating on scalars, we clear the overload. - match e.node { - ast::ExprBinary(ref op, ref lhs, ref rhs) => { - let lhs_ty = self.fcx.expr_ty(lhs); - let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty); - let rhs_ty = self.fcx.expr_ty(rhs); - let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty); - if ty::type_is_scalar(lhs_ty) && ty::type_is_scalar(rhs_ty) { - self.fcx.inh.method_map.borrow_mut().remove(&MethodCall::expr(e.id)); - - // weird but true: the by-ref binops put an - // adjustment on the lhs but not the rhs; the - // adjustment for rhs is kind of baked into the - // system. - if !ast_util::is_by_value_binop(op.node) { - self.fcx.inh.adjustments.borrow_mut().remove(&lhs.id); - } - } - } - _ => { } - } + self.fix_scalar_binary_expr(e); self.visit_node_id(ResolvingExpr(e.span), e.id); self.visit_method_map_entry(ResolvingExpr(e.span), MethodCall::expr(e.id)); - match e.node { - ast::ExprClosure(_, ref decl, _) => { - for input in &decl.inputs { - let _ = self.visit_node_id(ResolvingExpr(e.span), - input.id); - } + if let ast::ExprClosure(_, ref decl, _) = e.node { + for input in &decl.inputs { + self.visit_node_id(ResolvingExpr(e.span), input.id); } - _ => {} } visit::walk_expr(self, e); From 9c1dfed2ba2946bbf9de787de647f5c58e336ae0 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 14 Apr 2015 21:17:14 +0300 Subject: [PATCH 3/4] Use node_ty instead of expr_ty in binary expr fixup --- src/librustc_typeck/check/writeback.rs | 4 ++-- src/test/compile-fail/issue-24363.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-24363.rs diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5eab90764d4..889975f0eb2 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -92,10 +92,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // operating on scalars, we clear the overload. fn fix_scalar_binary_expr(&mut self, e: &ast::Expr) { if let ast::ExprBinary(ref op, ref lhs, ref rhs) = e.node { - let lhs_ty = self.fcx.expr_ty(lhs.id); + let lhs_ty = self.fcx.node_ty(lhs.id); let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty); - let rhs_ty = self.fcx.expr_ty(rhs.id); + let rhs_ty = self.fcx.node_ty(rhs.id); let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty); if ty::type_is_scalar(lhs_ty) && ty::type_is_scalar(rhs_ty) { diff --git a/src/test/compile-fail/issue-24363.rs b/src/test/compile-fail/issue-24363.rs new file mode 100644 index 00000000000..590c464371c --- /dev/null +++ b/src/test/compile-fail/issue-24363.rs @@ -0,0 +1,16 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + 1.create_a_type_error[ //~ ERROR attempted access of field + ()+() //~ ERROR binary operation `+` cannot be applied + // ^ ensure that we typeck the inner expression ^ + ]; +} From fd8c592757144b8d0655aaf1ff3dd3c5b8b16a80 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 15 Apr 2015 19:53:19 +0300 Subject: [PATCH 4/4] Always type-check the index of an IndexExpr Fixes #24363. --- src/librustc_typeck/check/mod.rs | 48 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8264647b256..402465355b6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3515,34 +3515,34 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } ast::ExprIndex(ref base, ref idx) => { check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref); + check_expr(fcx, &**idx); + let base_t = fcx.expr_ty(&**base); + let idx_t = fcx.expr_ty(&**idx); + if ty::type_is_error(base_t) { fcx.write_ty(id, base_t); + } else if ty::type_is_error(idx_t) { + fcx.write_ty(id, idx_t); } else { - check_expr(fcx, &**idx); - let idx_t = fcx.expr_ty(&**idx); - if ty::type_is_error(idx_t) { - fcx.write_ty(id, idx_t); - } else { - let base_t = structurally_resolved_type(fcx, expr.span, base_t); - match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) { - Some((index_ty, element_ty)) => { - let idx_expr_ty = fcx.expr_ty(idx); - demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty); - fcx.write_ty(id, element_ty); - } - None => { - check_expr_has_type(fcx, &**idx, fcx.tcx().types.err); - fcx.type_error_message( - expr.span, - |actual| { - format!("cannot index a value of type `{}`", - actual) - }, - base_t, - None); - fcx.write_ty(id, fcx.tcx().types.err); - } + let base_t = structurally_resolved_type(fcx, expr.span, base_t); + match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) { + Some((index_ty, element_ty)) => { + let idx_expr_ty = fcx.expr_ty(idx); + demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty); + fcx.write_ty(id, element_ty); + } + None => { + check_expr_has_type(fcx, &**idx, fcx.tcx().types.err); + fcx.type_error_message( + expr.span, + |actual| { + format!("cannot index a value of type `{}`", + actual) + }, + base_t, + None); + fcx.write_ty(id, fcx.tcx().types.err); } } }