From c01bfbd02b57a1aa9d8a39cd907f799d23c2a230 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 12 Dec 2017 14:50:09 -0200 Subject: [PATCH 1/9] refactor `structurally_resolve_type` the `or_else` part was dead code. --- src/librustc_typeck/check/mod.rs | 36 ++++++++------------------------ 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6147743437b8e..cb80498f3e204 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4954,41 +4954,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) - -> Ty<'tcx> - where F: Fn() -> Ty<'tcx> - { + // Resolves `typ` by a single level if `typ` is a type variable. If no + // resolution is possible, then an error is reported. + pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let mut ty = self.resolve_type_vars_with_obligations(ty); - if ty.is_ty_var() { - let alternative = f(); - // If not, error. - if alternative.is_ty_var() || alternative.references_error() { - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); - } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; - } else { - self.demand_suptype(sp, alternative, ty); - ty = alternative; + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); } + self.demand_suptype(sp, self.tcx.types.err, ty); + ty = self.tcx.types.err; } - ty } - // Resolves `typ` by a single level if `typ` is a type variable. If no - // resolution is possible, then an error is reported. - pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - self.structurally_resolve_type_or_else(sp, ty, || { - self.tcx.types.err - }) - } - fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, ctxt: BreakableCtxt<'gcx, 'tcx>, f: F) -> (BreakableCtxt<'gcx, 'tcx>, R) { From 3d83fc914a0f116ad0e4412d5ccc0be24b3b7af2 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 13 Dec 2017 12:35:26 -0200 Subject: [PATCH 2/9] Lazy numeric fallback. This refactoring tries to make numeric fallback easier to reason about. Instead of applying all fallbacks at an arbitrary point in the middle of inference, we apply the fallback only when necessary and only for the variable that requires it, which for numeric fallback turns out to be just casts. The only visible consequence seems to be some error messages where instead of getting `i32` we get `{integer}` because we are less eager about fallback. The bigger goal is to make it easier to integrate user fallbacks into inference, if we ever figure that out. --- src/librustc/ty/sty.rs | 7 ++ src/librustc_typeck/check/cast.rs | 4 +- src/librustc_typeck/check/mod.rs | 110 +++++++++++------- .../derived-errors/issue-31997.rs | 4 +- .../interior-mutability.stderr | 12 +- .../ui/mismatched_types/issue-26480.stderr | 2 +- 6 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index db7e4fe45ef76..d38ceb619e3cc 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1290,6 +1290,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + pub fn is_ty_infer(&self) -> bool { + match self.sty { + TyInfer(_) => true, + _ => false, + } + } + pub fn is_phantom_data(&self) -> bool { if let TyAdt(def, _) = self.sty { def.is_phantom_data() diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 48bd7b14fc96a..bc157d6feeafb 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -392,8 +392,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); + self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); + self.cast_ty = fcx.resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cb80498f3e204..aff96e39cfc72 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,9 +858,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze(body); fcx.select_obligations_where_possible(); + fcx.closure_analyze(body); fcx.check_casts(); fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); @@ -2129,13 +2128,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether + /// unconstrained types get replaced with ! or () (depending on whether /// feature(never_type) is enabled), unconstrained ints with i32, and /// unconstrained floats with f64. fn default_type_parameters(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - // Defaulting inference variables becomes very dubious if we have // encountered type-checking errors. Therefore, if we think we saw // some errors in this function, just resolve all uninstanted type @@ -2152,34 +2148,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for ty in &self.unsolved_variables() { let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { - debug!("default_type_parameters: defaulting `{:?}` to `i32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32) - }, - UnconstrainedFloat => { - debug!("default_type_parameters: defaulting `{:?}` to `f32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64) - } - Neither => { } - } + if resolved.is_ty_infer() { + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); } } } - // Implements type inference fallback algorithm - fn select_all_obligations_and_apply_defaults(&self) { - self.select_obligations_where_possible(); - self.default_type_parameters(); - self.select_obligations_where_possible(); + fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { + assert!(ty.is_ty_infer()); + if self.type_var_diverges(ty) { + debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", ty); + self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.mk_diverging_default()); + } + } + + fn apply_numeric_fallback_to_type(&self, ty: Ty<'tcx>) { + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + + assert!(ty.is_ty_infer()); + let fallback = match self.type_is_unconstrained_numeric(ty) { + UnconstrainedInt => self.tcx.types.i32, + UnconstrainedFloat => self.tcx.types.f64, + Neither => return, + }; + debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); + self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); } fn select_all_obligations_or_error(&self) { @@ -2189,7 +2184,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // resolutions are handled by now. assert!(self.deferred_call_resolutions.borrow().is_empty()); - self.select_all_obligations_and_apply_defaults(); + self.select_obligations_where_possible(); + self.default_type_parameters(); let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4954,21 +4950,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - // Resolves `typ` by a single level if `typ` is a type variable. If no - // resolution is possible, then an error is reported. + // Resolves `typ` by a single level if `typ` is a type variable. + // If no resolution is possible, then an error is reported. + // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let mut ty = self.resolve_type_vars_with_obligations(ty); - if ty.is_ty_var() { - // If not, error. - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); + if !ty.is_ty_var() { + ty + } else { + // Try divering fallback. + self.apply_diverging_fallback_to_type(ty); + ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_var() { + ty + } else { // Fallback failed, error. + self.must_be_known_in_context(sp, ty) } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; } - ty + } + + // Same as `structurally_resolved_type` but also resolves numeric vars, with fallback. + pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let mut ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_infer() { + return ty; + } else { + // Try diverging or numeric fallback. + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); + ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_infer() { + ty + } else { // Fallback failed, error. + self.must_be_known_in_context(sp, ty) + } + } + } + + fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + self.tcx.types.err } fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs index 2e1d3c55a8f4d..0385e3b8365d1 100644 --- a/src/test/compile-fail/derived-errors/issue-31997.rs +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -20,7 +20,9 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope + try!(closure(|| bar(0 as *mut _))); + //~^ ERROR cannot find function `bar` in this scope + //~^^ ERROR cannot cast to a pointer of an unknown kind Ok(()) } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index f4beb44b82dc7..dca9ab1b5415c 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` +error[E0277]: the trait bound `std::cell::UnsafeCell<{integer}>: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell<{integer}>` --> $DIR/interior-mutability.rs:15:5 | 15 | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ the type std::cell::UnsafeCell<{integer}> may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell]` + = help: within `std::cell::Cell<{integer}>`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<{integer}>` + = note: required because it appears within the type `std::cell::Cell<{integer}>` + = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell<{integer}>` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell<{integer}>]` = note: required by `std::panic::catch_unwind` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 5d25cb2f93c15..1b056486ad95b 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error[E0605]: non-primitive cast: `{integer}` as `()` +error[E0605]: non-primitive cast: `i32` as `()` --> $DIR/issue-26480.rs:32:19 | 32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast From f3cd4a7f64c50ff5935f4d507ae1103c93b8a2ad Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 13 Dec 2017 13:56:57 -0200 Subject: [PATCH 3/9] Refactor away `fn default_type_parameters` It had only one caller. --- src/librustc_typeck/check/mod.rs | 46 ++++++++++++-------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aff96e39cfc72..666b8e06522ea 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2127,34 +2127,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether - /// feature(never_type) is enabled), unconstrained ints with i32, and - /// unconstrained floats with f64. - fn default_type_parameters(&self) { - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. Therefore, if we think we saw - // some errors in this function, just resolve all uninstanted type - // varibles to TyError. - if self.is_tainted_by_errors() { - for ty in &self.unsolved_variables() { - if let ty::TyInfer(_) = self.shallow_resolve(ty).sty { - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } - } - return; - } - - for ty in &self.unsolved_variables() { - let resolved = self.resolve_type_vars_if_possible(ty); - if resolved.is_ty_infer() { - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); - } - } - } - fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { assert!(ty.is_ty_infer()); if self.type_var_diverges(ty) { @@ -2185,7 +2157,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(self.deferred_call_resolutions.borrow().is_empty()); self.select_obligations_where_possible(); - self.default_type_parameters(); + + // Apply fallbacks to unsolved variables. + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled), unconstrained ints with i32, + // unconstrained floats with f64. + for ty in &self.unsolved_variables() { + if self.is_tainted_by_errors() { + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. In that case, + // just resolve all uninstanted type variables to TyError. + debug!("default_type_parameters: defaulting `{:?}` to error", ty); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); + } else { + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); + } + } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); From 02084f3304acfa68e79d213a5ebd1c3478680741 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 18 Dec 2017 17:31:23 -0200 Subject: [PATCH 4/9] No fallback in `structurally_resolve_types`. Further refactoring. Put all fallback in `apply_fallback_if_possible`. --- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/mod.rs | 50 ++++++------------- .../{issue-26480.rs => issue-26480-1.rs} | 6 +-- .../ui/mismatched_types/issue-26480-1.stderr | 11 ++++ src/test/ui/mismatched_types/issue-26480-2.rs | 18 +++++++ .../ui/mismatched_types/issue-26480-2.stderr | 13 +++++ .../ui/mismatched_types/issue-26480.stderr | 13 +---- 7 files changed, 59 insertions(+), 54 deletions(-) rename src/test/ui/mismatched_types/{issue-26480.rs => issue-26480-1.rs} (91%) create mode 100644 src/test/ui/mismatched_types/issue-26480-1.stderr create mode 100644 src/test/ui/mismatched_types/issue-26480-2.rs create mode 100644 src/test/ui/mismatched_types/issue-26480-2.stderr diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bc157d6feeafb..631f7a740c4bb 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -393,7 +393,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); - self.cast_ty = fcx.resolved_type(self.span, self.cast_ty); + self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 666b8e06522ea..610510c5c74ed 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2127,23 +2127,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { - assert!(ty.is_ty_infer()); - if self.type_var_diverges(ty) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.mk_diverging_default()); - } - } - - fn apply_numeric_fallback_to_type(&self, ty: Ty<'tcx>) { + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled), unconstrained ints with i32, + // unconstrained floats with f64. + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. In that case, fallback to TyError. + fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; assert!(ty.is_ty_infer()); let fallback = match self.type_is_unconstrained_numeric(ty) { + _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither => return, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); @@ -2158,21 +2158,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); - // Apply fallbacks to unsolved variables. - // Non-numerics get replaced with ! or () (depending on whether - // feature(never_type) is enabled), unconstrained ints with i32, - // unconstrained floats with f64. for ty in &self.unsolved_variables() { - if self.is_tainted_by_errors() { - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. In that case, - // just resolve all uninstanted type variables to TyError. - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } else { - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); - } + self.apply_fallback_if_possible(ty); } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4942,18 +4929,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If no resolution is possible, then an error is reported. // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.resolve_type_vars_with_obligations(ty); + let ty = self.resolve_type_vars_with_obligations(ty); if !ty.is_ty_var() { ty } else { - // Try divering fallback. - self.apply_diverging_fallback_to_type(ty); - ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_var() { - ty - } else { // Fallback failed, error. - self.must_be_known_in_context(sp, ty) - } + self.must_be_known_in_context(sp, ty) } } @@ -4963,9 +4943,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !ty.is_ty_infer() { return ty; } else { - // Try diverging or numeric fallback. - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); + self.apply_fallback_if_possible(ty); ty = self.resolve_type_vars_with_obligations(ty); if !ty.is_ty_infer() { ty diff --git a/src/test/ui/mismatched_types/issue-26480.rs b/src/test/ui/mismatched_types/issue-26480-1.rs similarity index 91% rename from src/test/ui/mismatched_types/issue-26480.rs rename to src/test/ui/mismatched_types/issue-26480-1.rs index 33c5e74fafa1f..36a30ccb0fc3d 100644 --- a/src/test/ui/mismatched_types/issue-26480.rs +++ b/src/test/ui/mismatched_types/issue-26480-1.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; @@ -28,12 +29,7 @@ macro_rules! write { }} } -macro_rules! cast { - ($x:expr) => ($x as ()) //~ ERROR non-primitive cast -} - fn main() { let hello = ['H', 'e', 'y']; write!(hello); - cast!(2); } diff --git a/src/test/ui/mismatched_types/issue-26480-1.stderr b/src/test/ui/mismatched_types/issue-26480-1.stderr new file mode 100644 index 0000000000000..326b427b0fbe6 --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-1.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/issue-26480-1.rs:27:19 + | +27 | $arr.len() * size_of($arr[0])); //~ ERROR mismatched types + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize +... +34 | write!(hello); + | -------------- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/ui/mismatched_types/issue-26480-2.rs b/src/test/ui/mismatched_types/issue-26480-2.rs new file mode 100644 index 0000000000000..7015e5909e9ba --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-2.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +macro_rules! cast { + ($x:expr) => ($x as ()) //~ ERROR non-primitive cast +} + +fn main() { + cast!(2); +} diff --git a/src/test/ui/mismatched_types/issue-26480-2.stderr b/src/test/ui/mismatched_types/issue-26480-2.stderr new file mode 100644 index 0000000000000..3f6dcccdedb4f --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-2.stderr @@ -0,0 +1,13 @@ +error[E0605]: non-primitive cast: `i32` as `()` + --> $DIR/issue-26480-2.rs:13:19 + | +13 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast + | ^^^^^^^^ +... +17 | cast!(2); + | --------- in this macro invocation + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to previous error + diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 1b056486ad95b..27698c864c3fb 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,16 +7,5 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error[E0605]: non-primitive cast: `i32` as `()` - --> $DIR/issue-26480.rs:32:19 - | -32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast - | ^^^^^^^^ -... -38 | cast!(2); - | --------- in this macro invocation - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: aborting due to 2 previous errors +error: aborting due to previous error From 4c0ff95e6ecd861741e868cc729afe0339a4b8c7 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 21 Dec 2017 07:40:54 -0200 Subject: [PATCH 5/9] Be more explicit about how and why we need fallback in targets of casts --- src/librustc_typeck/check/cast.rs | 10 +++++++-- src/librustc_typeck/check/mod.rs | 29 +++++++++---------------- src/test/run-pass/cast-does-fallback.rs | 16 ++++++++++++++ 3 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/cast-does-fallback.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 631f7a740c4bb..8dde3d7ab98ac 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::{Diverges, FnCtxt}; +use super::{Diverges, Fallback, FnCtxt}; use errors::DiagnosticBuilder; use hir::def_id::DefId; @@ -392,7 +392,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); + self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); + // For backwards compatibility we apply numeric fallback here. This means that in: + // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. + if self.expr_ty.is_ty_infer() { + fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric); + self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); + } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 610510c5c74ed..e97de581173d5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1724,6 +1724,12 @@ enum TupleArgumentsFlag { TupleArguments, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Fallback { + Full, + Numeric +} + impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -2133,7 +2139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // unconstrained floats with f64. // Defaulting inference variables becomes very dubious if we have // encountered type-checking errors. In that case, fallback to TyError. - fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) { + fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2142,7 +2148,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither if self.type_var_diverges(ty) && fallback == Fallback::Full + => self.tcx.mk_diverging_default(), Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); @@ -2159,7 +2166,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); for ty in &self.unsolved_variables() { - self.apply_fallback_if_possible(ty); + self.apply_fallback_if_possible(ty, Fallback::Full); } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4937,22 +4944,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - // Same as `structurally_resolved_type` but also resolves numeric vars, with fallback. - pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_infer() { - return ty; - } else { - self.apply_fallback_if_possible(ty); - ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_infer() { - ty - } else { // Fallback failed, error. - self.must_be_known_in_context(sp, ty) - } - } - } - fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { if !self.is_tainted_by_errors() { type_error_struct!(self.tcx.sess, sp, ty, E0619, diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs new file mode 100644 index 0000000000000..86d6e387b2552 --- /dev/null +++ b/src/test/run-pass/cast-does-fallback.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let cap = 512 * 512; + cap as u8; + // Assert `cap` did not get inferred to `u8` and overflowed. + assert_ne!(cap, 0); +} From cd4de4cece143e8dbaeeff93492afcbb356d3051 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 18 Jan 2018 10:38:33 -0200 Subject: [PATCH 6/9] Suppress unknown cast errors in the presence of other errors. --- src/librustc_typeck/check/cast.rs | 3 +++ src/librustc_typeck/check/mod.rs | 8 ++++++-- .../compile-fail/derived-errors/issue-31997.rs | 4 +--- src/test/ui/issue-45730.rs | 4 ++++ src/test/ui/issue-45730.stderr | 8 ++++---- .../ui/mismatched_types/issue-26480-1.stderr | 11 ----------- src/test/ui/mismatched_types/issue-26480-2.rs | 18 ------------------ .../ui/mismatched_types/issue-26480-2.stderr | 13 ------------- .../{issue-26480-1.rs => issue-26480.rs} | 6 +++++- .../ui/mismatched_types/issue-26480.stderr | 13 ++++++++++++- 10 files changed, 35 insertions(+), 53 deletions(-) delete mode 100644 src/test/ui/mismatched_types/issue-26480-1.stderr delete mode 100644 src/test/ui/mismatched_types/issue-26480-2.rs delete mode 100644 src/test/ui/mismatched_types/issue-26480-2.stderr rename src/test/ui/mismatched_types/{issue-26480-1.rs => issue-26480.rs} (91%) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 8dde3d7ab98ac..2978921fc6200 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -290,6 +290,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { + if fcx.is_tainted_by_errors() { + return; + } let unknown_cast_to = match e { CastError::UnknownCastPtrKind => true, CastError::UnknownExprPtrKind => false, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e97de581173d5..57e40ec19af7d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2148,8 +2148,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) && fallback == Fallback::Full - => self.tcx.mk_diverging_default(), + Neither if self.type_var_diverges(ty) => { + match fallback { + Fallback::Full => self.tcx.mk_diverging_default(), + Fallback::Numeric => return, + } + } Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs index 0385e3b8365d1..2e1d3c55a8f4d 100644 --- a/src/test/compile-fail/derived-errors/issue-31997.rs +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -20,9 +20,7 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(0 as *mut _))); - //~^ ERROR cannot find function `bar` in this scope - //~^^ ERROR cannot cast to a pointer of an unknown kind + try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope Ok(()) } diff --git a/src/test/ui/issue-45730.rs b/src/test/ui/issue-45730.rs index d733c8e6de26f..1fe0b1ae2d241 100644 --- a/src/test/ui/issue-45730.rs +++ b/src/test/ui/issue-45730.rs @@ -11,9 +11,13 @@ use std::fmt; fn main() { let x: *const _ = 0 as _; //~ ERROR cannot cast +} +fn a() { let x: *const _ = 0 as *const _; //~ ERROR cannot cast let y: Option<*const fmt::Debug> = Some(x) as _; +} +fn c() { let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast } diff --git a/src/test/ui/issue-45730.stderr b/src/test/ui/issue-45730.stderr index 94d39239117ad..13205eead4361 100644 --- a/src/test/ui/issue-45730.stderr +++ b/src/test/ui/issue-45730.stderr @@ -9,9 +9,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:15:23 + --> $DIR/issue-45730.rs:17:23 | -15 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast +17 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast | ^^^^^-------- | | | help: consider giving more type information @@ -19,9 +19,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:18:13 + --> $DIR/issue-45730.rs:22:13 | -18 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast +22 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | help: consider giving more type information diff --git a/src/test/ui/mismatched_types/issue-26480-1.stderr b/src/test/ui/mismatched_types/issue-26480-1.stderr deleted file mode 100644 index 326b427b0fbe6..0000000000000 --- a/src/test/ui/mismatched_types/issue-26480-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-26480-1.rs:27:19 - | -27 | $arr.len() * size_of($arr[0])); //~ ERROR mismatched types - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize -... -34 | write!(hello); - | -------------- in this macro invocation - -error: aborting due to previous error - diff --git a/src/test/ui/mismatched_types/issue-26480-2.rs b/src/test/ui/mismatched_types/issue-26480-2.rs deleted file mode 100644 index 7015e5909e9ba..0000000000000 --- a/src/test/ui/mismatched_types/issue-26480-2.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// compile-flags: --error-format=human - -macro_rules! cast { - ($x:expr) => ($x as ()) //~ ERROR non-primitive cast -} - -fn main() { - cast!(2); -} diff --git a/src/test/ui/mismatched_types/issue-26480-2.stderr b/src/test/ui/mismatched_types/issue-26480-2.stderr deleted file mode 100644 index 3f6dcccdedb4f..0000000000000 --- a/src/test/ui/mismatched_types/issue-26480-2.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0605]: non-primitive cast: `i32` as `()` - --> $DIR/issue-26480-2.rs:13:19 - | -13 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast - | ^^^^^^^^ -... -17 | cast!(2); - | --------- in this macro invocation - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: aborting due to previous error - diff --git a/src/test/ui/mismatched_types/issue-26480-1.rs b/src/test/ui/mismatched_types/issue-26480.rs similarity index 91% rename from src/test/ui/mismatched_types/issue-26480-1.rs rename to src/test/ui/mismatched_types/issue-26480.rs index 36a30ccb0fc3d..33c5e74fafa1f 100644 --- a/src/test/ui/mismatched_types/issue-26480-1.rs +++ b/src/test/ui/mismatched_types/issue-26480.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: --error-format=human extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; @@ -29,7 +28,12 @@ macro_rules! write { }} } +macro_rules! cast { + ($x:expr) => ($x as ()) //~ ERROR non-primitive cast +} + fn main() { let hello = ['H', 'e', 'y']; write!(hello); + cast!(2); } diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 27698c864c3fb..5d25cb2f93c15 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,5 +7,16 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error: aborting due to previous error +error[E0605]: non-primitive cast: `{integer}` as `()` + --> $DIR/issue-26480.rs:32:19 + | +32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast + | ^^^^^^^^ +... +38 | cast!(2); + | --------- in this macro invocation + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to 2 previous errors From f8c140465f20217913f14b7423f7110d0cc7b57c Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 27 Jan 2018 15:42:23 -0200 Subject: [PATCH 7/9] Only closure analysis should run after fallback. Move `check_casts` and `resolve_generator_interiors` to before fallback. Rename `apply_fallback_if_possible` to `fallback_if_possible`. Refactor `select_all_obligations_or_error`. --- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/mod.rs | 36 +++++++++---------- .../interior-mutability.stderr | 12 +++---- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 2978921fc6200..dae5ba14bfb5b 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -399,7 +399,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // For backwards compatibility we apply numeric fallback here. This means that in: // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. if self.expr_ty.is_ty_infer() { - fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric); + fcx.fallback_if_possible(self.expr_ty, Fallback::Numeric); self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 57e40ec19af7d..b1645ed922830 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,9 +858,19 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; + fcx.check_casts(); + + // All type checking constraints were added, try to fallback unsolved variables. + fcx.select_obligations_where_possible(); + for ty in &fcx.unsolved_variables() { + fcx.fallback_if_possible(ty, Fallback::Full); + } fcx.select_obligations_where_possible(); + + // Closure and generater analysis may run after fallback + // because they doen't constrain other type variables. fcx.closure_analyze(body); - fcx.check_casts(); + assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); @@ -2137,9 +2147,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Non-numerics get replaced with ! or () (depending on whether // feature(never_type) is enabled), unconstrained ints with i32, // unconstrained floats with f64. - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. In that case, fallback to TyError. - fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { + // Fallback becomes very dubious if we have encountered type-checking errors. + // In that case, fallback to TyError. + fn fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2162,22 +2172,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); - - // upvar inference should have ensured that all deferred call - // resolutions are handled by now. - assert!(self.deferred_call_resolutions.borrow().is_empty()); - - self.select_obligations_where_possible(); - - for ty in &self.unsolved_variables() { - self.apply_fallback_if_possible(ty, Fallback::Full); - } - - let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); - - match fulfillment_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); } + if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { + self.report_fulfillment_errors(&errors, self.inh.body_id); } } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index dca9ab1b5415c..f4beb44b82dc7 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell<{integer}>: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell<{integer}>` +error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` --> $DIR/interior-mutability.rs:15:5 | 15 | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell<{integer}> may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::Cell<{integer}>`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<{integer}>` - = note: required because it appears within the type `std::cell::Cell<{integer}>` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell<{integer}>` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell<{integer}>]` + = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` + = note: required because it appears within the type `std::cell::Cell` + = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell]` = note: required by `std::panic::catch_unwind` error: aborting due to previous error From b813718f6dff49b851fcd18a5674640554bda2e5 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 27 Jan 2018 18:17:44 -0200 Subject: [PATCH 8/9] Refactor away `fn must_be_known_in_context` --- src/librustc_typeck/check/mod.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b1645ed922830..0395b3eb4aa2d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4940,18 +4940,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !ty.is_ty_var() { ty } else { - self.must_be_known_in_context(sp, ty) - } - } - - fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + self.tcx.types.err } - self.demand_suptype(sp, self.tcx.types.err, ty); - self.tcx.types.err } fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, From d49d428f791b97c476c066deb9c2b3c20165199f Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 8 Feb 2018 17:36:17 -0200 Subject: [PATCH 9/9] Revert checking casts before fallback. This turns out to not be backwards compatible. --- src/librustc_typeck/check/cast.rs | 11 +---------- src/librustc_typeck/check/mod.rs | 25 ++++++++----------------- src/test/run-pass/cast-does-fallback.rs | 4 ++++ src/test/ui/issue-45730.rs | 4 ---- src/test/ui/issue-45730.stderr | 8 ++++---- 5 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index dae5ba14bfb5b..48bd7b14fc96a 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::{Diverges, Fallback, FnCtxt}; +use super::{Diverges, FnCtxt}; use errors::DiagnosticBuilder; use hir::def_id::DefId; @@ -290,9 +290,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { - if fcx.is_tainted_by_errors() { - return; - } let unknown_cast_to = match e { CastError::UnknownCastPtrKind => true, CastError::UnknownExprPtrKind => false, @@ -396,12 +393,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - // For backwards compatibility we apply numeric fallback here. This means that in: - // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. - if self.expr_ty.is_ty_infer() { - fcx.fallback_if_possible(self.expr_ty, Fallback::Numeric); - self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0395b3eb4aa2d..f50bd03a9e07b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,17 +858,19 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.check_casts(); - // All type checking constraints were added, try to fallback unsolved variables. fcx.select_obligations_where_possible(); for ty in &fcx.unsolved_variables() { - fcx.fallback_if_possible(ty, Fallback::Full); + fcx.fallback_if_possible(ty); } fcx.select_obligations_where_possible(); + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + fcx.check_casts(); + // Closure and generater analysis may run after fallback - // because they doen't constrain other type variables. + // because they don't constrain other type variables. fcx.closure_analyze(body); assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); @@ -1734,12 +1736,6 @@ enum TupleArgumentsFlag { TupleArguments, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Fallback { - Full, - Numeric -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -2149,7 +2145,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // unconstrained floats with f64. // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to TyError. - fn fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { + fn fallback_if_possible(&self, ty: Ty<'tcx>) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2158,12 +2154,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => { - match fallback { - Fallback::Full => self.tcx.mk_diverging_default(), - Fallback::Numeric => return, - } - } + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs index 86d6e387b2552..aa6752ffc35b0 100644 --- a/src/test/run-pass/cast-does-fallback.rs +++ b/src/test/run-pass/cast-does-fallback.rs @@ -9,6 +9,10 @@ // except according to those terms. pub fn main() { + // Test that these type check correctly. + (&42u8 >> 4) as usize; + (&42u8 << 4) as usize; + let cap = 512 * 512; cap as u8; // Assert `cap` did not get inferred to `u8` and overflowed. diff --git a/src/test/ui/issue-45730.rs b/src/test/ui/issue-45730.rs index 1fe0b1ae2d241..d733c8e6de26f 100644 --- a/src/test/ui/issue-45730.rs +++ b/src/test/ui/issue-45730.rs @@ -11,13 +11,9 @@ use std::fmt; fn main() { let x: *const _ = 0 as _; //~ ERROR cannot cast -} -fn a() { let x: *const _ = 0 as *const _; //~ ERROR cannot cast let y: Option<*const fmt::Debug> = Some(x) as _; -} -fn c() { let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast } diff --git a/src/test/ui/issue-45730.stderr b/src/test/ui/issue-45730.stderr index 13205eead4361..94d39239117ad 100644 --- a/src/test/ui/issue-45730.stderr +++ b/src/test/ui/issue-45730.stderr @@ -9,9 +9,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:17:23 + --> $DIR/issue-45730.rs:15:23 | -17 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast +15 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast | ^^^^^-------- | | | help: consider giving more type information @@ -19,9 +19,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:22:13 + --> $DIR/issue-45730.rs:18:13 | -22 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast +18 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | help: consider giving more type information