diff options
| -rw-r--r-- | lib/compiler/src/compile.erl | 7 | ||||
| -rw-r--r-- | lib/compiler/src/v3_kernel.erl | 4 | ||||
| -rw-r--r-- | lib/stdlib/examples/erl_id_trans.erl | 151 | ||||
| -rw-r--r-- | lib/stdlib/src/epp.erl | 15 | ||||
| -rw-r--r-- | lib/stdlib/src/erl_expand_records.erl | 36 | ||||
| -rw-r--r-- | lib/stdlib/src/erl_lint.erl | 29 | ||||
| -rw-r--r-- | lib/stdlib/src/ms_transform.erl | 13 | ||||
| -rw-r--r-- | lib/stdlib/src/qlc_pt.erl | 6 | ||||
| -rw-r--r-- | lib/stdlib/src/shell.erl | 8 | ||||
| -rw-r--r-- | lib/stdlib/test/epp_SUITE.erl | 21 | ||||
| -rw-r--r-- | lib/stdlib/test/erl_lint_SUITE.erl | 17 | ||||
| -rw-r--r-- | lib/stdlib/test/ms_transform_SUITE.erl | 6 | ||||
| -rw-r--r-- | lib/stdlib/test/shell_SUITE.erl | 4 | ||||
| -rw-r--r-- | lib/tools/test/cover_SUITE_data/d.erl | 2 | 
14 files changed, 214 insertions, 105 deletions
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 72f1a767ed..46917905de 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -1620,11 +1620,8 @@ output_encoding(F, #compile{encoding = Encoding}) ->      ok = io:setopts(F, [{encoding, Encoding}]),      ok = io:fwrite(F, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]). -restore_expanded_types("P", Fs) -> -    epp:restore_typed_record_fields(Fs);  restore_expanded_types("E", {M,I,Fs0}) -> -    Fs1 = restore_expand_module(Fs0), -    Fs = epp:restore_typed_record_fields(Fs1), +    Fs = restore_expand_module(Fs0),      {M,I,Fs};  restore_expanded_types(_Ext, Code) -> Code. @@ -1636,6 +1633,8 @@ restore_expand_module([{attribute,Line,spec,[Arg]}|Fs]) ->      [{attribute,Line,spec,Arg}|restore_expand_module(Fs)];  restore_expand_module([{attribute,Line,callback,[Arg]}|Fs]) ->      [{attribute,Line,callback,Arg}|restore_expand_module(Fs)]; +restore_expand_module([{attribute,Line,record,[R]}|Fs]) -> +    [{attribute,Line,record,R}|restore_expand_module(Fs)];  restore_expand_module([F|Fs]) ->      [F|restore_expand_module(Fs)];  restore_expand_module([]) -> []. diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 011748df3a..4446d5ff1d 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 1999-2013. All Rights Reserved. +%% Copyright Ericsson AB 1999-2015. All Rights Reserved.  %%  %% Licensed under the Apache License, Version 2.0 (the "License");  %% you may not use this file except in compliance with the License. @@ -143,8 +143,10 @@ attributes([]) -> [].  include_attribute(type) -> false;  include_attribute(spec) -> false; +include_attribute(callback) -> false;  include_attribute(opaque) -> false;  include_attribute(export_type) -> false; +include_attribute(record) -> false;  include_attribute(_) -> true.  function({#c_var{name={F,Arity}=FA},Body}, St0) -> diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl index 529ae30862..c2e345763a 100644 --- a/lib/stdlib/examples/erl_id_trans.erl +++ b/lib/stdlib/examples/erl_id_trans.erl @@ -18,11 +18,11 @@  %%  -module(erl_id_trans). -%% A identity transformer of Erlang abstract syntax. +%% An identity transformer of Erlang abstract syntax.  %% This module only traverses legal Erlang code. This is most noticeable  %% in guards where only a limited number of expressions are allowed. -%% N.B. if this module is to be used as a basis for tranforms then +%% N.B. if this module is to be used as a basis for transforms then  %% all the error cases must be handled otherwise this module just crashes!  -export([parse_transform/2]). @@ -53,6 +53,17 @@ form({attribute,Line,export,Es0}) ->  form({attribute,Line,import,{Mod,Is0}}) ->      Is1 = farity_list(Is0),      {attribute,Line,import,{Mod,Is1}}; +form({attribute,Line,export_type,Es0}) -> +    Es1 = farity_list(Es0), +    {attribute,Line,export_type,Es1}; +form({attribute,Line,optional_callbacks,Es0}) -> +    try farity_list(Es0) of +        Es1 -> +            {attribute,Line,optional_callbacks,Es1} +    catch +        _:_ -> +            {attribute,Line,optional_callbacks,Es0} +    end;  form({attribute,Line,compile,C}) ->      {attribute,Line,compile,C};  form({attribute,Line,record,{Name,Defs0}}) -> @@ -60,14 +71,28 @@ form({attribute,Line,record,{Name,Defs0}}) ->      {attribute,Line,record,{Name,Defs1}};  form({attribute,Line,asm,{function,N,A,Code}}) ->      {attribute,Line,asm,{function,N,A,Code}}; +form({attribute,Line,type,{N,T,Vs}}) -> +    T1 = type(T), +    Vs1 = variable_list(Vs), +    {attribute,Line,type,{N,T1,Vs1}}; +form({attribute,Line,opaque,{N,T,Vs}}) -> +    T1 = type(T), +    Vs1 = variable_list(Vs), +    {attribute,Line,opaque,{N,T1,Vs1}}; +form({attribute,Line,spec,{{N,A},FTs}}) -> +    FTs1 = function_type_list(FTs), +    {attribute,Line,spec,{{N,A},FTs1}}; +form({attribute,Line,spec,{{M,N,A},FTs}}) -> +    FTs1 = function_type_list(FTs), +    {attribute,Line,spec,{{M,N,A},FTs1}}; +form({attribute,Line,callback,{{N,A},FTs}}) -> +    FTs1 = function_type_list(FTs), +    {attribute,Line,callback,{{N,A},FTs1}};  form({attribute,Line,Attr,Val}) ->		%The general attribute.      {attribute,Line,Attr,Val};  form({function,Line,Name0,Arity0,Clauses0}) ->      {Name,Arity,Clauses} = function(Name0, Arity0, Clauses0),      {function,Line,Name,Arity,Clauses}; -% Mnemosyne, ignore... -form({rule,Line,Name,Arity,Body}) -> -    {rule,Line,Name,Arity,Body}; % Dont dig into this  %% Extra forms from the parser.  form({error,E}) -> {error,E};  form({warning,W}) -> {warning,W}; @@ -79,6 +104,12 @@ farity_list([{Name,Arity}|Fas]) ->      [{Name,Arity}|farity_list(Fas)];  farity_list([]) -> []. +%% -type variable_list([Var]) -> [Var] + +variable_list([{var,Line,Var}|Vs]) -> +    [{var,Line,Var}|variable_list(Vs)]; +variable_list([]) -> []. +  %% -type record_defs([RecDef]) -> [RecDef].  %%  N.B. Field names are full expressions here but only atoms are allowed  %%  by the *parser*! @@ -88,6 +119,16 @@ record_defs([{record_field,Line,{atom,La,A},Val0}|Is]) ->      [{record_field,Line,{atom,La,A},Val1}|record_defs(Is)];  record_defs([{record_field,Line,{atom,La,A}}|Is]) ->      [{record_field,Line,{atom,La,A}}|record_defs(Is)]; +record_defs([{typed_record_field,{record_field,Line,{atom,La,A},Val0},Type}| +             Is]) -> +    Val1 = expr(Val0), +    Type1 = type(Type), +    [{typed_record_field,{record_field,Line,{atom,La,A},Val1},Type1}| +     record_defs(Is)]; +record_defs([{typed_record_field,{record_field,Line,{atom,La,A}},Type}|Is]) -> +    Type1 = type(Type), +    [{typed_record_field,{record_field,Line,{atom,La,A}},Type1}| +     record_defs(Is)];  record_defs([]) -> [].  %% -type function(atom(), integer(), [Clause]) -> {atom(),integer(),[Clause]}. @@ -196,9 +237,9 @@ pattern_grp([]) ->  bit_types([]) ->      []; -bit_types([Atom | Rest]) when atom(Atom) -> +bit_types([Atom | Rest]) when is_atom(Atom) ->      [Atom | bit_types(Rest)]; -bit_types([{Atom, Integer} | Rest]) when atom(Atom), integer(Integer) -> +bit_types([{Atom, Integer} | Rest]) when is_atom(Atom), is_integer(Integer) ->      [{Atom, Integer} | bit_types(Rest)]. @@ -226,7 +267,7 @@ pattern_fields([]) -> [].  %% -type guard([GuardTest]) -> [GuardTest]. -guard([G0|Gs]) when list(G0) -> +guard([G0|Gs]) when is_list(G0) ->      [guard0(G0) | guard(Gs)];  guard(L) ->      guard0(L). @@ -547,3 +588,97 @@ fun_clauses([C0|Cs]) ->      C1 = clause(C0),      [C1|fun_clauses(Cs)];  fun_clauses([]) -> []. + +function_type_list([{type,Line,bounded_fun,[Ft,Fc]}|Fts]) -> +    Ft1 = function_type(Ft), +    Fc1 = function_constraint(Fc), +    [{type,Line,bounded_fun,[Ft1,Fc1]}|function_type_list(Fts)]; +function_type_list([Ft|Fts]) -> +    [function_type(Ft)|function_type_list(Fts)]; +function_type_list([]) -> []. + +function_type({type,Line,'fun',[{type,Lt,product,As},B]}) -> +    As1 = type_list(As), +    B1 = type(B), +    {type,Line,'fun',[{type,Lt,product,As1},B1]}. + +function_constraint([C|Cs]) -> +    C1 = constraint(C), +    [C1|function_constraint(Cs)]; +function_constraint([]) -> []. + +constraint({type,Line,constraint,[{atom,L,A},[V,T]]}) -> +    V1 = type(V), +    T1 = type(T), +    {type,Line,constraint,[{atom,L,A},[V1,T1]]}. + +type({ann_type,Line,[{var,Lv,V},T]}) -> +    T1 = type(T), +    {ann_type,Line,[{var,Lv,V},T1]}; +type({atom,Line,A}) -> +    {atom,Line,A}; +type({integer,Line,I}) -> +    {integer,Line,I}; +type({op,Line,Op,T}) -> +    T1 = type(T), +    {op,Line,Op,T1}; +type({op,Line,Op,L,R}) -> +    L1 = type(L), +    R1 = type(R), +    {op,Line,Op,L1,R1}; +type({type,Line,binary,[M,N]}) -> +    M1 = type(M), +    N1 = type(N), +    {type,Line,binary,[M1,N1]}; +type({type,Line,'fun',[]}) -> +    {type,Line,'fun',[]}; +type({type,Line,'fun',[{type,Lt,any},B]}) -> +    B1 = type(B), +    {type,Line,'fun',[{type,Lt,any},B1]}; +type({type,Line,range,[L,H]}) -> +    L1 = type(L), +    H1 = type(H), +    {type,Line,range,[L1,H1]}; +type({type,Line,map,any}) -> +    {type,Line,map,any}; +type({type,Line,map,Ps}) -> +    Ps1 = map_pair_types(Ps), +    {type,Line,map,Ps1}; +type({type,Line,record,[{atom,La,N}|Fs]}) -> +    Fs1 = field_types(Fs), +    {type,Line,record,[{atom,La,N}|Fs1]}; +type({remote_type,Line,[{atom,Lm,M},{atom,Ln,N},As]}) -> +    As1 = type_list(As), +    {remote_type,Line,[{atom,Lm,M},{atom,Ln,N},As1]}; +type({type,Line,tuple,any}) -> +    {type,Line,tuple,any}; +type({type,Line,tuple,Ts}) -> +    Ts1 = type_list(Ts), +    {type,Line,tuple,Ts1}; +type({type,Line,union,Ts}) -> +    Ts1 = type_list(Ts), +    {type,Line,union,Ts1}; +type({var,Line,V}) -> +    {var,Line,V}; +type({user_type,Line,N,As}) -> +    As1 = type_list(As), +    {user_type,Line,N,As1}; +type({type,Line,N,As}) -> +    As1 = type_list(As), +    {type,Line,N,As1}. + +map_pair_types([{type,Line,map_field_assoc,[K,V]}|Ps]) -> +    K1 = type(K), +    V1 = type(V), +    [{type,Line,map_field_assoc,[K1,V1]}|map_pair_types(Ps)]; +map_pair_types([]) -> []. + +field_types([{type,Line,field_type,[{atom,La,A},T]}|Fs]) -> +    T1 = type(T), +    [{type,Line,field_type,[{atom,La,A},T1]}|field_types(Fs)]; +field_types([]) -> []. + +type_list([T|Ts]) -> +    T1 = type(T), +    [T1|type_list(Ts)]; +type_list([]) -> []. diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index 45f616bb02..be7c2ec346 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -258,20 +258,7 @@ parse_file(Ifile, Options) ->  parse_file(Epp) ->      case parse_erl_form(Epp) of  	{ok,Form} -> -	    case Form of -		{attribute,La,record,{Record, Fields}} -> -		    case normalize_typed_record_fields(Fields) of -			{typed, NewFields} -> -			    [{attribute, La, record, {Record, NewFields}}, -			     {attribute, La, type, -			      {{record, Record}, Fields, []}} -			     |parse_file(Epp)]; -			not_typed -> -			    [Form|parse_file(Epp)] -		    end; -		_ -> -		    [Form|parse_file(Epp)] -	    end; +            [Form|parse_file(Epp)];  	{error,E} ->  	    [{error,E}|parse_file(Epp)];  	{eof,Location} -> diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl index bcfeef7321..9c0a7fb7d5 100644 --- a/lib/stdlib/src/erl_expand_records.erl +++ b/lib/stdlib/src/erl_expand_records.erl @@ -33,8 +33,6 @@                   vcount=0,            % Variable counter                   imports=[],          % Imports                   records=dict:new(),  % Record definitions -		 trecords=sets:new(), % Typed records -		 uses_types=false,    % Are there -spec or -type in the module                   strict_ra=[],        % strict record accesses                   checked_ra=[]        % successfully accessed records                  }). @@ -47,45 +45,18 @@  %% erl_lint without errors.  module(Fs0, Opts0) ->      Opts = compiler_options(Fs0) ++ Opts0, -    TRecs = typed_records(Fs0), -    UsesTypes = uses_types(Fs0), -    St0 = #exprec{compile = Opts, trecords = TRecs, uses_types = UsesTypes}, +    St0 = #exprec{compile = Opts},      {Fs,_St} = forms(Fs0, St0),      Fs.  compiler_options(Forms) ->      lists:flatten([C || {attribute,_,compile,C} <- Forms]). -typed_records(Fs) -> -    typed_records(Fs, sets:new()). - -typed_records([{attribute,_L,type,{{record, Name},_Defs,[]}} | Fs], Trecs) -> -    typed_records(Fs, sets:add_element(Name, Trecs)); -typed_records([_|Fs], Trecs) -> -    typed_records(Fs, Trecs); -typed_records([], Trecs) -> -    Trecs. - -uses_types([{attribute,_L,spec,_}|_]) -> true; -uses_types([{attribute,_L,type,_}|_]) -> true; -uses_types([{attribute,_L,opaque,_}|_]) -> true; -uses_types([_|Fs]) -> uses_types(Fs); -uses_types([]) -> false. -     -forms([{attribute,L,record,{Name,Defs}} | Fs], St0) -> +forms([{attribute,_,record,{Name,Defs}}=Attr | Fs], St0) ->      NDefs = normalise_fields(Defs),      St = St0#exprec{records=dict:store(Name, NDefs, St0#exprec.records)},      {Fs1, St1} = forms(Fs, St), -    %% Check if we need to keep the record information for usage in types. -    case St#exprec.uses_types of -	true -> -	    case sets:is_element(Name, St#exprec.trecords) of -		true -> {Fs1, St1}; -		false -> {[{attribute,L,type,{{record,Name},Defs,[]}}|Fs1], St1} -	    end; -	false -> -	    {Fs1, St1} -    end; +    {[Attr | Fs1], St1};  forms([{attribute,L,import,Is} | Fs0], St0) ->      St1 = import(Is, St0),      {Fs,St2} = forms(Fs0, St1), @@ -513,7 +484,6 @@ lc_tq(Line, [F0 | Qs0], St0) ->  lc_tq(_Line, [], St0) ->      {[],St0#exprec{checked_ra = []}}. -  %% normalise_fields([RecDef]) -> [Field].  %%  Normalise the field definitions to always have a default value. If  %%  none has been given then use 'undefined'. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 8d2df1cf66..4ca9a609a8 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -360,6 +360,9 @@ format_error({redefine_type, {TypeName, Arity}}) ->  		  [TypeName, gen_type_paren(Arity)]);  format_error({type_syntax, Constr}) ->      io_lib:format("bad ~w type", [Constr]); +format_error(old_abstract_code) -> +    io_lib:format("abstract code generated before Erlang/OTP 19.0 and " +                  "having typed record fields cannot be compiled", []);  format_error({redefine_spec, {M, F, A}}) ->      io_lib:format("spec for ~w:~w/~w already defined", [M, F, A]);  format_error({redefine_spec, {F, A}}) -> @@ -1143,7 +1146,7 @@ check_untyped_records(Forms, St0) ->  	    RecNames = dict:fetch_keys(St0#lint.records),  	    %% these are the records with field(s) containing type info  	    TRecNames = [Name || -			    {attribute,_,type,{{record,Name},Fields,_}} <- Forms, +			    {attribute,_,record,{Name,Fields}} <- Forms,  			    lists:all(fun ({typed_record_field,_,_}) -> true;  					  (_) -> false  				      end, Fields)], @@ -1153,7 +1156,8 @@ check_untyped_records(Forms, St0) ->  			      [] -> St; % exclude records with no fields  			      [_|_] -> add_warning(L, {untyped_record, N}, St)  			  end -		  end, St0, RecNames -- TRecNames); +		  end, St0, ordsets:subtract(ordsets:from_list(RecNames), +                                             ordsets:from_list(TRecNames)));  	false ->  	    St0      end. @@ -2443,7 +2447,10 @@ record_def(Line, Name, Fs0, St0) ->          true -> add_error(Line, {redefine_record,Name}, St0);          false ->              {Fs1,St1} = def_fields(normalise_fields(Fs0), Name, St0), -            St1#lint{records=dict:store(Name, {Line,Fs1}, St1#lint.records)} +            St2 = St1#lint{records=dict:store(Name, {Line,Fs1}, +                                              St1#lint.records)}, +            Types = [T || {typed_record_field, _, T} <- Fs0], +            check_type({type, nowarn(), product, Types}, St2)      end.  %% def_fields([RecDef], RecordName, State) -> {[DefField],State}. @@ -2646,11 +2653,6 @@ find_field(_F, []) -> error.  %%    Attr :: 'type' | 'opaque'  %% Checks that a type definition is valid. -type_def(_Attr, _Line, {record, _RecName}, Fields, [], St0) -> -    %% The record field names and such are checked in the record format. -    %% We only need to check the types. -    Types = [T || {typed_record_field, _, T} <- Fields], -    check_type({type, nowarn(), product, Types}, St0);  type_def(Attr, Line, TypeName, ProtoType, Args, St0) ->      TypeDefs = St0#lint.types,      Arity = length(Args), @@ -2813,6 +2815,8 @@ check_type({user_type, L, TypeName, Args}, SeenVars, St) ->      lists:foldl(fun(T, {AccSeenVars, AccSt}) ->  			check_type(T, AccSeenVars, AccSt)  		end, {SeenVars, St1}, Args); +check_type([{typed_record_field,Field,_T}|_], SeenVars, St) -> +    {SeenVars, add_error(element(2, Field), old_abstract_code, St)};  check_type(I, SeenVars, St) ->      case erl_eval:partial_eval(I) of          {integer,_ILn,_Integer} -> {SeenVars, St}; @@ -2994,9 +2998,10 @@ add_missing_spec_warnings(Forms, St0, Type) ->  		[{FA,L} || {function,L,F,A,_} <- Forms,  			   not lists:member(FA = {F,A}, Specs)];  	    exported -> -		Exps = gb_sets:to_list(St0#lint.exports) -- pseudolocals(), +		Exps0 = gb_sets:to_list(St0#lint.exports) -- pseudolocals(), +                Exps = Exps0 -- Specs,  		[{FA,L} || {function,L,F,A,_} <- Forms, -			   member(FA = {F,A}, Exps -- Specs)] +			   member(FA = {F,A}, Exps)]  	end,      foldl(fun ({FA,L}, St) ->  		  add_warning(L, {missing_spec,FA}, St) @@ -3009,7 +3014,9 @@ check_unused_types(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) ->  	    L = gb_sets:to_list(ExpTs) ++ dict:fetch_keys(D),  	    UsedTypes = gb_sets:from_list(L),  	    FoldFun = -		fun(Type, #typeinfo{line = FileLine}, AccSt) -> +                fun({{record, _}=_Type, 0}, _, AccSt) -> +                        AccSt; % Before Erlang/OTP 19.0 +                   (Type, #typeinfo{line = FileLine}, AccSt) ->                          case loc(FileLine, AccSt) of  			    {FirstFile, _} ->  				case gb_sets:is_member(Type, UsedTypes) of diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index b67b6f75d7..24b5fde1db 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -307,15 +307,18 @@ cleanup_filename({Old,OldRec,OldWarnings}) ->  add_record_definition({Name,FieldList}) ->      {KeyList,_} = lists:foldl( -		    fun({record_field,_,{atom,Line0,FieldName}},{L,C}) -> -			    {[{FieldName,C,{atom,Line0,undefined}}|L],C+1}; -		       ({record_field,_,{atom,_,FieldName},Def},{L,C}) -> -			    {[{FieldName,C,Def}|L],C+1} -		    end, +                    fun(F, {L,C}) -> {[record_field(F, C)|L],C+1} end,  		    {[],2},  		    FieldList),      put_records([{Name,KeyList}|get_records()]). +record_field({record_field,_,{atom,Line0,FieldName}}, C) -> +    {FieldName,C,{atom,Line0,undefined}}; +record_field({record_field,_,{atom,_,FieldName},Def}, C) -> +    {FieldName,C,Def}; +record_field({typed_record_field,Field,_Type}, C) -> +    record_field(Field, C). +  forms([F0|Fs0]) ->      F1 = form(F0),      Fs1 = forms(Fs0), diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 9f69cd5003..e4b9768b12 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -1914,9 +1914,9 @@ expand_pattern_records(P, State) ->  expand_expr_records(E, State) ->      RecordDefs = State#state.records,      A = anno1(), -    Forms = RecordDefs ++ [{function,A,foo,0,[{clause,A,[],[],[pe(E)]}]}], -    [{function,_,foo,0,[{clause,_,[],[],[NE]}]}] =  -        erl_expand_records:module(Forms, [no_strict_record_tests]), +    Forms0 = RecordDefs ++ [{function,A,foo,0,[{clause,A,[],[],[pe(E)]}]}], +    Forms = erl_expand_records:module(Forms0, [no_strict_record_tests]), +    {function,_,foo,0,[{clause,_,[],[],[NE]}]} = lists:last(Forms),      NE.  %% Partial evaluation. diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index ce1d9eb0ff..82a3a2be4f 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -917,9 +917,9 @@ expand_records(UsedRecords, E0) ->      RecordDefs = [Def || {_Name,Def} <- UsedRecords],      L = erl_anno:new(1),      E = prep_rec(E0), -    Forms = RecordDefs ++ [{function,L,foo,0,[{clause,L,[],[],[E]}]}], -    [{function,L,foo,0,[{clause,L,[],[],[NE]}]}] =  -        erl_expand_records:module(Forms, [strict_record_tests]),  +    Forms0 = RecordDefs ++ [{function,L,foo,0,[{clause,L,[],[],[E]}]}], +    Forms = erl_expand_records:module(Forms0, [strict_record_tests]), +    {function,L,foo,0,[{clause,L,[],[],[NE]}]} = lists:last(Forms),      prep_rec(NE).  prep_rec({value,_CommandN,_V}=Value) -> @@ -1081,6 +1081,8 @@ record_fields([{record_field,_,{atom,_,Field}} | Fs]) ->      [Field | record_fields(Fs)];  record_fields([{record_field,_,{atom,_,Field},_} | Fs]) ->      [Field | record_fields(Fs)]; +record_fields([{typed_record_field,Field,_Type} | Fs]) -> +    record_fields([Field | Fs]);  record_fields([]) ->      []. diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl index 4c007e76ad..955b482313 100644 --- a/lib/stdlib/test/epp_SUITE.erl +++ b/lib/stdlib/test/epp_SUITE.erl @@ -25,7 +25,7 @@  	 upcase_mac_1/1, upcase_mac_2/1,  	 variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1,           pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1, -         otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1, +         otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1,           otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1,           otp_11728/1, encoding/1, extends/1]). @@ -68,7 +68,7 @@ all() ->      [rec_1, {group, upcase_mac}, include_local, predef_mac,       {group, variable}, otp_4870, otp_4871, otp_5362, pmod,       not_circular, skip_header, otp_6277, otp_7702, otp_8130, -     overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, +     overload_mac, otp_8388, otp_8470, otp_8562,       otp_8665, otp_8911, otp_10302, otp_10820, otp_11728,       encoding, extends]. @@ -1230,23 +1230,8 @@ otp_8470(Config) when is_list(Config) ->      ?line receive _ -> fail() after 0 -> ok end,      ok. -otp_8503(doc) -> -    ["OTP-8503. Record with no fields is considered typed."]; -otp_8503(suite) -> -    []; -otp_8503(Config) when is_list(Config) -> -    Dir = ?config(priv_dir, Config), -    C = <<"-record(r, {}).">>, -    ?line File = filename:join(Dir, "otp_8503.erl"), -    ?line ok = file:write_file(File, C), -    ?line {ok, List} = epp:parse_file(File, [], []), -    ?line [_] = [F || {attribute,_,type,{{record,r},[],[]}}=F <- List], -    file:delete(File), -    ?line receive _ -> fail() after 0 -> ok end, -    ok. -  otp_8562(doc) -> -    ["OTP-8503. Record with no fields is considered typed."]; +    ["OTP-8562. Record with no fields is considered typed."];  otp_8562(suite) ->      [];  otp_8562(Config) when is_list(Config) -> diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 32247ba492..8f0ac828ec 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -2607,6 +2607,23 @@ otp_5878(Config) when is_list(Config) ->                    ">>,      ?line [] = run_test2(Config, UsedByType, [warn_unused_record]), +    %% Abstract code generated by OTP 18. Note that the type info for +    %% record fields has been put in a separate form. +    OldAbstract = [{attribute,1,file,{"rec.erl",1}}, +                   {attribute,1,module,rec}, +                   {attribute,3,export,[{t,0}]}, +                   {attribute,7,record,{r,[{record_field,7,{atom,7,f}}]}}, +                   {attribute,7,type, +                    {{record,r}, +                     [{typed_record_field, +                       {record_field,7,{atom,7,f}}, +                       {type,7,union,[{atom,7,undefined},{type,7,atom,[]}]}}], +                     []}}, +                   {function,9,t,0,[{clause,9,[],[],[{record,10,r,[]}]}]}, +                   {eof,11}], +    {error,[{"rec.erl",[{7,erl_lint,old_abstract_code}]}],[]} = +        compile:forms(OldAbstract, [return, report]), +      ok.  otp_6885(doc) -> diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl index f02e82b39c..5f2167b609 100644 --- a/lib/stdlib/test/ms_transform_SUITE.erl +++ b/lib/stdlib/test/ms_transform_SUITE.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2015. All Rights Reserved.  %%  %% Licensed under the Apache License, Version 2.0 (the "License");  %% you may not use this file except in compliance with the License. @@ -342,8 +342,8 @@ records(doc) ->  records(Config) when is_list(Config) ->      ?line setup(Config),      ?line RD = <<"-record(t, {" -	             "t1 = []," -	             "t2 = foo," +	             "t1 = [] :: list()," +	             "t2 = foo :: atom(),"  	             "t3,"  	             "t4"  	            "}).">>, diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl index a9dd6b5817..3fb1a5572d 100644 --- a/lib/stdlib/test/shell_SUITE.erl +++ b/lib/stdlib/test/shell_SUITE.erl @@ -393,7 +393,9 @@ records(Config) when is_list(Config) ->      Test = filename:join(?config(priv_dir, Config), "test.erl"),      Contents = <<"-module(test). -                  -record(state, {bin, reply, leader}). +                  -record(state, {bin :: binary(), +                                  reply = no, +                                  leader = some :: atom()}).                    -ifdef(test1).                    -record(test1, {f}). diff --git a/lib/tools/test/cover_SUITE_data/d.erl b/lib/tools/test/cover_SUITE_data/d.erl index 696e27e49b..b1d8ebd62e 100644 --- a/lib/tools/test/cover_SUITE_data/d.erl +++ b/lib/tools/test/cover_SUITE_data/d.erl @@ -6,7 +6,7 @@  	 size/0]).  -export([init/0]). % spawn --record(person, {name, age, location, moved=false}). +-record(person, {name, age :: integer(), location, moved=false :: boolean()}).  %%%----------------------------------------------------------------------  %%% User interface functions  | 
