diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index bbd12c9671d28..1b9d6ec6c33b6 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1177,6 +1177,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { ast::Return(ref ret_ty) => ast::Return( self.rebuild_arg_ty_or_output(&**ret_ty, lifetime, anon_nums, region_names) ), + ast::DefaultReturn(span) => ast::DefaultReturn(span), ast::NoReturn(span) => ast::NoReturn(span) } } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index a03a5090c050b..ea66b97bbf968 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -1450,18 +1450,15 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let mut signature = Vec::with_capacity(fn_decl.inputs.len() + 1); // Return type -- llvm::DIBuilder wants this at index 0 - match fn_decl.output { - ast::Return(ref ret_ty) if ret_ty.node == ast::TyTup(vec![]) => - signature.push(ptr::null_mut()), - _ => { - assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); - - let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id); - let return_type = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &return_type); - signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP)); - } + assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); + let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id); + let return_type = monomorphize::apply_param_substs(cx.tcx(), + param_substs, + &return_type); + if ty::type_is_nil(return_type) { + signature.push(ptr::null_mut()) + } else { + signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP)); } // Arguments types diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index abb961d87de96..c989d2311be36 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -445,9 +445,8 @@ fn gate_simd_ffi(tcx: &ty::ctxt, decl: &ast::FnDecl, ty: &ty::BareFnTy) { for (input, ty) in decl.inputs.iter().zip(sig.inputs.iter()) { check(&*input.ty, *ty) } - match decl.output { - ast::NoReturn(_) => {} - ast::Return(ref ty) => check(&**ty, sig.output.unwrap()) + if let ast::Return(ref ty) = decl.output { + check(&**ty, sig.output.unwrap()) } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f2927dfd84340..c2b34acc6c8cc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1359,7 +1359,8 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, implied_output_region, lifetimes_for_params, &**output)), - ast::NoReturn(_) => ty::FnDiverging + ast::DefaultReturn(..) => ty::FnConverging(ty::mk_nil(this.tcx())), + ast::NoReturn(..) => ty::FnDiverging }; (ty::BareFnTy { @@ -1486,14 +1487,21 @@ pub fn ty_of_closure<'tcx>( let expected_ret_ty = expected_sig.map(|e| e.output); + let is_infer = match decl.output { + ast::Return(ref output) if output.node == ast::TyInfer => true, + ast::DefaultReturn(..) => true, + _ => false + }; + let output_ty = match decl.output { - ast::Return(ref output) if output.node == ast::TyInfer && expected_ret_ty.is_some() => + _ if is_infer && expected_ret_ty.is_some() => expected_ret_ty.unwrap(), - ast::Return(ref output) if output.node == ast::TyInfer => - ty::FnConverging(this.ty_infer(output.span)), + _ if is_infer => + ty::FnConverging(this.ty_infer(decl.output.span())), ast::Return(ref output) => ty::FnConverging(ast_ty_to_ty(this, &rb, &**output)), - ast::NoReturn(_) => ty::FnDiverging + ast::DefaultReturn(..) => unreachable!(), + ast::NoReturn(..) => ty::FnDiverging }; debug!("ty_of_closure: input_tys={}", input_tys.repr(this.tcx())); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c56952abc4419..25ba7ccdbc4d9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1488,7 +1488,9 @@ fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, let output = match decl.output { ast::Return(ref ty) => ty::FnConverging(ast_ty_to_ty(ccx, &rb, &**ty)), - ast::NoReturn(_) => + ast::DefaultReturn(..) => + ty::FnConverging(ty::mk_nil(ccx.tcx)), + ast::NoReturn(..) => ty::FnDiverging }; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8dc3adad3b27a..7342c9f3e81de 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1141,6 +1141,7 @@ impl Clean for ast::Arg { #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)] pub enum FunctionRetTy { Return(Type), + DefaultReturn, NoReturn } @@ -1148,7 +1149,8 @@ impl Clean for ast::FunctionRetTy { fn clean(&self, cx: &DocContext) -> FunctionRetTy { match *self { ast::Return(ref typ) => Return(typ.clean(cx)), - ast::NoReturn(_) => NoReturn + ast::DefaultReturn(..) => DefaultReturn, + ast::NoReturn(..) => NoReturn } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d13936b216865..57b8d666c95b7 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -557,6 +557,7 @@ impl fmt::String for clean::FunctionRetTy { match *self { clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()), clean::Return(ref ty) => write!(f, " -> {}", ty), + clean::DefaultReturn => Ok(()), clean::NoReturn => write!(f, " -> !") } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0ea429116b0bb..fcf80410da240 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1390,6 +1390,10 @@ pub enum FunctionRetTy { /// Functions with return type ! that always /// raise an error or exit (i.e. never return to the caller) NoReturn(Span), + /// Return type is not specified. Functions default to () and + /// closures default to inference. Span points to where return + /// type would be inserted. + DefaultReturn(Span), /// Everything else Return(P), } @@ -1398,6 +1402,7 @@ impl FunctionRetTy { pub fn span(&self) -> Span { match *self { NoReturn(span) => span, + DefaultReturn(span) => span, Return(ref ty) => ty.span } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 16c29c9b5eb33..f484650ad5b06 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -726,6 +726,7 @@ pub fn noop_fold_fn_decl(decl: P, fld: &mut T) -> P { inputs: inputs.move_map(|x| fld.fold_arg(x)), output: match output { Return(ty) => Return(fld.fold_ty(ty)), + DefaultReturn(span) => DefaultReturn(span), NoReturn(span) => NoReturn(span) }, variadic: variadic @@ -1189,14 +1190,7 @@ pub fn noop_fold_foreign_item(ni: P, folder: &mut T) -> attrs: attrs.move_map(|x| folder.fold_attribute(x)), node: match node { ForeignItemFn(fdec, generics) => { - ForeignItemFn(fdec.map(|FnDecl {inputs, output, variadic}| FnDecl { - inputs: inputs.move_map(|a| folder.fold_arg(a)), - output: match output { - Return(ty) => Return(folder.fold_ty(ty)), - NoReturn(span) => NoReturn(span) - }, - variadic: variadic - }), folder.fold_generics(generics)) + ForeignItemFn(folder.fold_fn_decl(fdec), folder.fold_generics(generics)) } ForeignItemStatic(t, m) => { ForeignItemStatic(folder.fold_ty(t), m) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index f1f547ba0c7dd..90e236dfde35b 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -1066,9 +1066,7 @@ mod test { }), id: ast::DUMMY_NODE_ID }), - output: ast::Return(P(ast::Ty{id: ast::DUMMY_NODE_ID, - node: ast::TyTup(vec![]), - span:sp(15,15)})), // not sure + output: ast::DefaultReturn(sp(15, 15)), variadic: false }), ast::Unsafety::Normal, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 30cc9836374fb..d4a02146c5e7d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -19,7 +19,8 @@ use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block}; use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause}; use ast::{Crate, CrateConfig, Decl, DeclItem}; -use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf}; +use ast::{DeclLocal, DefaultBlock, DefaultReturn}; +use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox}; use ast::{ExprBreak, ExprCall, ExprCast}; @@ -1426,11 +1427,7 @@ impl<'a> Parser<'a> { } } else { let pos = self.span.lo; - Return(P(Ty { - id: ast::DUMMY_NODE_ID, - node: TyTup(vec![]), - span: mk_sp(pos, pos), - })) + DefaultReturn(mk_sp(pos, pos)) } } @@ -4548,15 +4545,7 @@ impl<'a> Parser<'a> { (optional_unboxed_closure_kind, args) } }; - let output = if self.check(&token::RArrow) { - self.parse_ret_ty() - } else { - Return(P(Ty { - id: ast::DUMMY_NODE_ID, - node: TyInfer, - span: self.span, - })) - }; + let output = self.parse_ret_ty(); (P(FnDecl { inputs: inputs_captures, @@ -4573,15 +4562,7 @@ impl<'a> Parser<'a> { seq_sep_trailing_allowed(token::Comma), |p| p.parse_fn_block_arg()); - let output = if self.check(&token::RArrow) { - self.parse_ret_ty() - } else { - Return(P(Ty { - id: ast::DUMMY_NODE_ID, - node: TyInfer, - span: self.span, - })) - }; + let output = self.parse_ret_ty(); P(FnDecl { inputs: inputs, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 5d76dc710060b..b59e770c6ba51 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2351,10 +2351,8 @@ impl<'a> State<'a> { try!(self.print_fn_args(decl, None)); try!(word(&mut self.s, "|")); - if let ast::Return(ref ty) = decl.output { - if ty.node == ast::TyInfer { - return self.maybe_print_comment(ty.span.lo); - } + if let ast::DefaultReturn(..) = decl.output { + return Ok(()); } try!(self.space_if_not_bol()); @@ -2364,6 +2362,7 @@ impl<'a> State<'a> { try!(self.print_type(&**ty)); self.maybe_print_comment(ty.span.lo) } + ast::DefaultReturn(..) => unreachable!(), ast::NoReturn(span) => { try!(self.word_nbsp("!")); self.maybe_print_comment(span.lo) @@ -2385,10 +2384,8 @@ impl<'a> State<'a> { try!(self.print_fn_args(decl, None)); try!(word(&mut self.s, ")")); - if let ast::Return(ref ty) = decl.output { - if ty.node == ast::TyInfer { - return self.maybe_print_comment(ty.span.lo); - } + if let ast::DefaultReturn(..) = decl.output { + return Ok(()); } try!(self.space_if_not_bol()); @@ -2398,6 +2395,7 @@ impl<'a> State<'a> { try!(self.print_type(&**ty)); self.maybe_print_comment(ty.span.lo) } + ast::DefaultReturn(..) => unreachable!(), ast::NoReturn(span) => { try!(self.word_nbsp("!")); self.maybe_print_comment(span.lo) @@ -2684,13 +2682,8 @@ impl<'a> State<'a> { } pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> IoResult<()> { - if let ast::Return(ref ty) = decl.output { - match ty.node { - ast::TyTup(ref tys) if tys.is_empty() => { - return self.maybe_print_comment(ty.span.lo); - } - _ => () - } + if let ast::DefaultReturn(..) = decl.output { + return Ok(()); } try!(self.space_if_not_bol()); @@ -2699,6 +2692,7 @@ impl<'a> State<'a> { match decl.output { ast::NoReturn(_) => try!(self.word_nbsp("!")), + ast::DefaultReturn(..) => unreachable!(), ast::Return(ref ty) => try!(self.print_type(&**ty)) } @@ -3071,9 +3065,7 @@ mod test { let decl = ast::FnDecl { inputs: Vec::new(), - output: ast::Return(P(ast::Ty {id: 0, - node: ast::TyTup(vec![]), - span: codemap::DUMMY_SP})), + output: ast::DefaultReturn(codemap::DUMMY_SP), variadic: false }; let generics = ast_util::empty_generics(); diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 895268f96c8a8..5f869d5093fec 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -297,11 +297,8 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { match &i.node { &ast::ItemFn(ref decl, _, _, ref generics, _) => { let no_output = match decl.output { - ast::Return(ref ret_ty) => match ret_ty.node { - ast::TyTup(ref tys) if tys.is_empty() => true, - _ => false, - }, - ast::NoReturn(_) => false + ast::DefaultReturn(..) => true, + _ => false }; if decl.inputs.is_empty() && no_output @@ -336,11 +333,8 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { ast::ItemFn(ref decl, _, _, ref generics, _) => { let input_cnt = decl.inputs.len(); let no_output = match decl.output { - ast::Return(ref ret_ty) => match ret_ty.node { - ast::TyTup(ref tys) if tys.is_empty() => true, - _ => false, - }, - ast::NoReturn(_) => false + ast::DefaultReturn(..) => true, + _ => false }; let tparm_cnt = generics.ty_params.len(); // NB: inadequate check, but we're running diff --git a/src/test/pretty/fn-return.rs b/src/test/pretty/fn-return.rs new file mode 100644 index 0000000000000..8a223296e5467 --- /dev/null +++ b/src/test/pretty/fn-return.rs @@ -0,0 +1,17 @@ +// 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. + +// pp-exact + +// Check that `fn f() -> () { }` does not print as `fn f() { }`. + +fn f() -> () { } + +fn main() { }