| 950 | | TypeCheckerResult obj_result, |
| 951 | | List<TypeCheckerResult> staticArgs_result) { |
| 952 | | Type t; |
| 953 | | ConstraintFormula accumulated_constraints = ConstraintFormula.TRUE; |
| 954 | | if( obj_result.type().isNone() ) { |
| 955 | | return TypeCheckerResult.compose(that, subtypeChecker, obj_result, |
| 956 | | TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); |
| 957 | | } |
| 958 | | else if( (obj_result.type().unwrap() instanceof TraitType) ) { |
| 959 | | t=obj_result.type().unwrap(); |
| 960 | | } |
| 961 | | else if( (obj_result.type().unwrap() instanceof _RewriteGenericSingletonType) ) { |
| 962 | | // instantiate with static parameters |
| 963 | | _RewriteGenericSingletonType uninstantiated_t = (_RewriteGenericSingletonType)obj_result.type().unwrap(); |
| 964 | | Option<ConstraintFormula> constraint = StaticTypeReplacer.argsMatchParams(that.getStaticArgs(), uninstantiated_t.getStaticParams(), this.subtypeChecker); |
| 965 | | if(constraint.isSome()) { |
| 966 | | // make a trait type that is GenericType instantiated |
| 967 | | t = NodeFactory.makeTraitType(uninstantiated_t.getSpan(), |
| 968 | | uninstantiated_t.isParenthesized(), uninstantiated_t.getName(), that.getStaticArgs()); |
| 969 | | accumulated_constraints = constraint.unwrap(); |
| 970 | | } |
| 971 | | else { |
| 972 | | // error |
| 973 | | String err = "Generic object, " + uninstantiated_t + " instantiated with invalid arguments, " + that.getStaticArgs(); |
| 974 | | TypeCheckerResult e_result = new TypeCheckerResult(that, TypeError.make(err, that)); |
| 975 | | return TypeCheckerResult.compose(that, subtypeChecker, obj_result, e_result, |
| 976 | | TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); |
| 977 | | } |
| 978 | | } |
| 979 | | else { |
| 980 | | return bug("Unexpected type for ObjectRef."); |
| 981 | | } |
| 982 | | |
| 983 | | Node new_node = new _RewriteObjectRef(that.getSpan(), that.isParenthesized(), Option.<Type>some(t), (Id) obj_result.ast(), (List<StaticArg>) TypeCheckerResult.astFromResults(staticArgs_result)); |
| 984 | | return TypeCheckerResult.compose(new_node, t, subtypeChecker, obj_result, |
| 985 | | TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result), |
| 986 | | new TypeCheckerResult(new_node,accumulated_constraints)); |
| | 950 | TypeCheckerResult obj_result, |
| | 951 | List<TypeCheckerResult> staticArgs_result) { |
| | 952 | Type t; |
| | 953 | ConstraintFormula accumulated_constraints = ConstraintFormula.TRUE; |
| | 954 | if( obj_result.type().isNone() ) { |
| | 955 | return TypeCheckerResult.compose(that, subtypeChecker, obj_result, |
| | 956 | TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); |
| | 957 | } |
| | 958 | else if( (obj_result.type().unwrap() instanceof TraitType) ) { |
| | 959 | t=obj_result.type().unwrap(); |
| | 960 | TraitType _t = (TraitType)t; |
| | 961 | |
| | 962 | if ( NodeUtil.isGenericSingletonType(_t) ) { |
| | 963 | // instantiate with static parameters |
| | 964 | Option<ConstraintFormula> constraint = StaticTypeReplacer.argsMatchParams(that.getStaticArgs(), |
| | 965 | _t.getStaticParams(), |
| | 966 | this.subtypeChecker); |
| | 967 | if(constraint.isSome()) { |
| | 968 | // make a trait type that is GenericType instantiated |
| | 969 | t = NodeFactory.makeTraitType(_t.getSpan(), |
| | 970 | _t.isParenthesized(), |
| | 971 | _t.getName(), |
| | 972 | that.getStaticArgs()); |
| | 973 | accumulated_constraints = constraint.unwrap(); |
| | 974 | } |
| | 975 | else { |
| | 976 | // error |
| | 977 | String err = "Generic object, " + _t + " instantiated with invalid arguments, " + that.getStaticArgs(); |
| | 978 | TypeCheckerResult e_result = new TypeCheckerResult(that, TypeError.make(err, that)); |
| | 979 | return TypeCheckerResult.compose(that, subtypeChecker, obj_result, e_result, |
| | 980 | TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); |
| | 981 | } |
| | 982 | } |
| | 983 | } |
| | 984 | else { |
| | 985 | return bug("Unexpected type for ObjectRef."); |
| | 986 | } |
| | 987 | |
| | 988 | Node new_node = new _RewriteObjectRef(that.getSpan(), that.isParenthesized(), |
| | 989 | Option.<Type>some(t), |
| | 990 | (Id) obj_result.ast(), |
| | 991 | (List<StaticArg>) TypeCheckerResult.astFromResults(staticArgs_result)); |
| | 992 | return TypeCheckerResult.compose(new_node, t, subtypeChecker, obj_result, |
| | 993 | TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result), |
| | 994 | new TypeCheckerResult(new_node,accumulated_constraints)); |
| 2970 | | TypeCheckerResult multiJuxt_result, |
| 2971 | | TypeCheckerResult infixJuxt_result, |
| 2972 | | List<TypeCheckerResult> exprs_result) { |
| 2973 | | // The implementation of this method is very similar to tight juxt except |
| 2974 | | // the ordering of association is different. |
| 2975 | | // Notice also that tightJuxt has to be recursive, but loose juxt is not, due to specification. |
| 2976 | | |
| 2977 | | // Did any subexpressions fail to typecheck? |
| 2978 | | for( TypeCheckerResult r : exprs_result ) { |
| 2979 | | if( r.type().isNone()) |
| 2980 | | return TypeCheckerResult.compose(that, subtypeChecker, exprs_result); |
| 2981 | | } |
| 2982 | | |
| 2983 | | if( that.getExprs().size() != exprs_result.size() ) { |
| 2984 | | bug("Number of types don't match number of sub-expressions"); |
| 2985 | | } |
| 2986 | | // Specification describes chunks, which are elements group together. Chunking process goes first. |
| 2987 | | List<Pair<TypeCheckerResult,Expr>> checked_chunks = new LinkedList<Pair<TypeCheckerResult,Expr>>(); |
| 2988 | | { |
| 2989 | | List<Pair<TypeCheckerResult,Expr>> cur_chunk = new LinkedList<Pair<TypeCheckerResult,Expr>>(); |
| 2990 | | Iterator<Expr> expr_iter = that.getExprs().iterator(); |
| 2991 | | boolean seen_non_fn = false; |
| 2992 | | // First the loose juxtaposition is broken into nonempty chunks; wherever there is a non-function element followed |
| 2993 | | // by a function element, the latter begins a new chunk. Thus a chunk consists of some number (possibly zero) of |
| 2994 | | // functions followed by some number (possibly zero) of non-functions. |
| 2995 | | for( TypeCheckerResult r : exprs_result ) { |
| 2996 | | boolean is_arrow = TypesUtil.isArrows(r.type().unwrap()); |
| 2997 | | if( is_arrow && seen_non_fn ) { |
| 2998 | | // finished last chunk |
| 2999 | | Pair<TypeCheckerResult,Expr> checked_chunk = this.checkChunk(cur_chunk, that.getInfixJuxt()); |
| 3000 | | checked_chunks.add(checked_chunk); |
| 3001 | | cur_chunk.clear(); |
| 3002 | | seen_non_fn = false; |
| 3003 | | } |
| 3004 | | if( is_arrow ){ |
| 3005 | | cur_chunk.add(Pair.make(r, expr_iter.next())); |
| 3006 | | } |
| 3007 | | else { |
| 3008 | | seen_non_fn = true; |
| 3009 | | cur_chunk.add(Pair.make(r, expr_iter.next())); |
| 3010 | | } |
| 3011 | | } |
| 3012 | | // Last chunk needs to be checked, if there is one |
| 3013 | | if( !cur_chunk.isEmpty() ) { |
| 3014 | | checked_chunks.add(checkChunk(cur_chunk, that.getInfixJuxt())); |
| 3015 | | } |
| 3016 | | } |
| 3017 | | // After chunking |
| 3018 | | List<Expr> new_juxt_exprs = CollectUtil.makeList(IterUtil.pairSeconds(checked_chunks)); |
| 3019 | | List<TypeCheckerResult> new_juxt_results = CollectUtil.makeList(IterUtil.pairFirsts(checked_chunks)); |
| 3020 | | |
| 3021 | | if( checked_chunks.size() == 1 ) { |
| 3022 | | Expr expr = IterUtil.first(new_juxt_exprs); |
| 3023 | | TypeCheckerResult expr_result = expr.accept(this); // Is it bad to re-typecheck all args? |
| 3024 | | return TypeCheckerResult.compose(expr_result.ast(), expr_result.type(), subtypeChecker, expr_result, |
| 3025 | | TypeCheckerResult.compose(expr_result.ast(), subtypeChecker, new_juxt_results)); |
| 3026 | | } |
| 3027 | | // (1) If any element that remains has type String, then it is a static error if any two adjacent elements are not of type String. |
| 3028 | | // TODO: Separate pass? |
| 3029 | | // (2) Treat the sequence that remains as a multifix application of the juxtaposition operator. The rules for multifix operators then apply: |
| 3030 | | OpExpr multi_op_expr = new OpExpr(that.getSpan(), that.getMultiJuxt(), new_juxt_exprs); |
| 3031 | | TypeCheckerResult multi_op_result = multi_op_expr.accept(this); |
| 3032 | | if( multi_op_result.type().isSome() ) { |
| 3033 | | return TypeCheckerResult.compose(multi_op_result.ast(), multi_op_result.type(), subtypeChecker, |
| 3034 | | TypeCheckerResult.compose(multi_op_result.ast(), subtypeChecker, new_juxt_results)); |
| 3035 | | } |
| 3036 | | // if an applicable method cannot be found for the entire expression, then it is left-associated. |
| 3037 | | Iterator<Expr> expr_iter = new_juxt_exprs.iterator(); |
| 3038 | | Expr expr_1 = expr_iter.next(); // the fact that >= two items are here is guaranteed from above. |
| 3039 | | Expr expr_2 = expr_iter.next(); |
| 3040 | | OpExpr cur_op_expr = new OpExpr(new Span(expr_1.getSpan(),expr_2.getSpan()), that.getInfixJuxt(), Useful.list(expr_1,expr_2)); |
| 3041 | | while( expr_iter.hasNext() ) { |
| 3042 | | Expr next_expr = expr_iter.next(); |
| 3043 | | cur_op_expr = new OpExpr(new Span(cur_op_expr.getSpan(),next_expr.getSpan()), that.getInfixJuxt(), Useful.list(cur_op_expr, next_expr)); |
| 3044 | | } |
| 3045 | | // typecheck this result instead |
| 3046 | | TypeCheckerResult op_expr_result = cur_op_expr.accept(this); // Is it bad to re-typecheck all args? |
| 3047 | | return TypeCheckerResult.compose(op_expr_result.ast(), op_expr_result.type(), subtypeChecker, op_expr_result, |
| 3048 | | TypeCheckerResult.compose(op_expr_result.ast(), subtypeChecker, new_juxt_results)); |
| | 2978 | TypeCheckerResult multiJuxt_result, |
| | 2979 | TypeCheckerResult infixJuxt_result, |
| | 2980 | List<TypeCheckerResult> exprs_result) { |
| | 2981 | // The implementation of this method is very similar to tight juxt except |
| | 2982 | // the ordering of association is different. |
| | 2983 | // Notice also that tightJuxt has to be recursive, but loose juxt is not, due to specification. |
| | 2984 | |
| | 2985 | // Did any subexpressions fail to typecheck? |
| | 2986 | for( TypeCheckerResult r : exprs_result ) { |
| | 2987 | if( r.type().isNone()) |
| | 2988 | return TypeCheckerResult.compose(that, subtypeChecker, exprs_result); |
| | 2989 | } |
| | 2990 | |
| | 2991 | if( that.getExprs().size() != exprs_result.size() ) { |
| | 2992 | bug("Number of types don't match number of sub-expressions"); |
| | 2993 | } |
| | 2994 | // Specification describes chunks, which are elements group together. Chunking process goes first. |
| | 2995 | List<Pair<TypeCheckerResult,Expr>> checked_chunks = new LinkedList<Pair<TypeCheckerResult,Expr>>(); |
| | 2996 | { |
| | 2997 | List<Pair<TypeCheckerResult,Expr>> cur_chunk = new LinkedList<Pair<TypeCheckerResult,Expr>>(); |
| | 2998 | Iterator<Expr> expr_iter = that.getExprs().iterator(); |
| | 2999 | boolean seen_non_fn = false; |
| | 3000 | // First the loose juxtaposition is broken into nonempty chunks; wherever there is a non-function element followed |
| | 3001 | // by a function element, the latter begins a new chunk. Thus a chunk consists of some number (possibly zero) of |
| | 3002 | // functions followed by some number (possibly zero) of non-functions. |
| | 3003 | for( TypeCheckerResult r : exprs_result ) { |
| | 3004 | boolean is_arrow = TypesUtil.isArrows(r.type().unwrap()); |
| | 3005 | if( is_arrow && seen_non_fn ) { |
| | 3006 | // finished last chunk |
| | 3007 | Pair<TypeCheckerResult,Expr> checked_chunk = this.checkChunk(cur_chunk, that.getInfixJuxt()); |
| | 3008 | checked_chunks.add(checked_chunk); |
| | 3009 | cur_chunk.clear(); |
| | 3010 | seen_non_fn = false; |
| | 3011 | } |
| | 3012 | if( is_arrow ){ |
| | 3013 | cur_chunk.add(Pair.make(r, expr_iter.next())); |
| | 3014 | } |
| | 3015 | else { |
| | 3016 | seen_non_fn = true; |
| | 3017 | cur_chunk.add(Pair.make(r, expr_iter.next())); |
| | 3018 | } |
| | 3019 | } |
| | 3020 | // Last chunk needs to be checked, if there is one |
| | 3021 | if( !cur_chunk.isEmpty() ) { |
| | 3022 | checked_chunks.add(checkChunk(cur_chunk, that.getInfixJuxt())); |
| | 3023 | } |
| | 3024 | } |
| | 3025 | // After chunking |
| | 3026 | List<Expr> new_juxt_exprs = CollectUtil.makeList(IterUtil.pairSeconds(checked_chunks)); |
| | 3027 | List<TypeCheckerResult> new_juxt_results = CollectUtil.makeList(IterUtil.pairFirsts(checked_chunks)); |
| | 3028 | |
| | 3029 | if( checked_chunks.size() == 1 ) { |
| | 3030 | Expr expr = IterUtil.first(new_juxt_exprs); |
| | 3031 | TypeCheckerResult expr_result = expr.accept(this); // Is it bad to re-typecheck all args? |
| | 3032 | return TypeCheckerResult.compose(expr_result.ast(), expr_result.type(), subtypeChecker, expr_result, |
| | 3033 | TypeCheckerResult.compose(expr_result.ast(), subtypeChecker, new_juxt_results)); |
| | 3034 | } |
| | 3035 | // (1) If any element that remains has type String, then it is a static error if any two adjacent elements are not of type String. |
| | 3036 | // TODO: Separate pass? |
| | 3037 | // (2) Treat the sequence that remains as a multifix application of the juxtaposition operator. The rules for multifix operators then apply: |
| | 3038 | OpExpr multi_op_expr = new OpExpr(that.getSpan(), that.getMultiJuxt(), new_juxt_exprs); |
| | 3039 | TypeCheckerResult multi_op_result = multi_op_expr.accept(this); |
| | 3040 | if( multi_op_result.type().isSome() ) { |
| | 3041 | return TypeCheckerResult.compose(multi_op_result.ast(), multi_op_result.type(), subtypeChecker, |
| | 3042 | TypeCheckerResult.compose(multi_op_result.ast(), subtypeChecker, new_juxt_results)); |
| | 3043 | } |
| | 3044 | // if an applicable method cannot be found for the entire expression, then it is left-associated. |
| | 3045 | Iterator<Expr> expr_iter = new_juxt_exprs.iterator(); |
| | 3046 | Expr expr_1 = expr_iter.next(); // the fact that >= two items are here is guaranteed from above. |
| | 3047 | Expr expr_2 = expr_iter.next(); |
| | 3048 | OpExpr cur_op_expr = new OpExpr(new Span(expr_1.getSpan(),expr_2.getSpan()), that.getInfixJuxt(), Useful.list(expr_1,expr_2)); |
| | 3049 | while( expr_iter.hasNext() ) { |
| | 3050 | Expr next_expr = expr_iter.next(); |
| | 3051 | cur_op_expr = new OpExpr(new Span(cur_op_expr.getSpan(),next_expr.getSpan()), that.getInfixJuxt(), Useful.list(cur_op_expr, next_expr)); |
| | 3052 | } |
| | 3053 | // typecheck this result instead |
| | 3054 | TypeCheckerResult op_expr_result = cur_op_expr.accept(this); // Is it bad to re-typecheck all args? |
| | 3055 | return TypeCheckerResult.compose(op_expr_result.ast(), op_expr_result.type(), subtypeChecker, op_expr_result, |
| | 3056 | TypeCheckerResult.compose(op_expr_result.ast(), subtypeChecker, new_juxt_results)); |
| 3860 | | // Just create a MathPrimary |
| 3861 | | Expr front = IterUtil.first(that.getExprs()); |
| 3862 | | |
| 3863 | | // If this juxt is actually a fn app, then rewrite to a fn app. |
| 3864 | | if (that.isFnApp()) { |
| 3865 | | // Make sure it is just two exprs. |
| 3866 | | if (that.getExprs().size() != 2) { |
| 3867 | | bug(String.format("TightJuxt denoted as function application but has %d (!= 2) exprs.", that.getExprs().size())); |
| 3868 | | } |
| 3869 | | Expr arg = that.getExprs().get(1); |
| 3870 | | _RewriteFnApp fnApp = new _RewriteFnApp(new Span(front.getSpan(), arg.getSpan()), |
| 3871 | | front, arg); |
| 3872 | | |
| 3873 | | // Simulate a TypeCheckerResult for the front, giving it a fresh arrow type. |
| 3874 | | Type freshArrow = NodeFactory.makeArrowType(new Span(), |
| 3875 | | NodeFactory.make_InferenceVarType(that.getSpan()), |
| 3876 | | NodeFactory.make_InferenceVarType(that.getSpan())); |
| 3877 | | TypeCheckerResult front_result = new TypeCheckerResult(front, freshArrow); |
| 3878 | | |
| 3879 | | // Type check the other nodes and recur on the fn app. |
| 3880 | | Option<TypeCheckerResult> exprType_result = this.recurOnOptionOfType(that.getExprType()); |
| 3881 | | TypeCheckerResult arg_result = arg.accept(this); |
| 3882 | | TypeCheckerResult fnApp_result = this.for_RewriteFnAppOnly(fnApp, |
| 3883 | | exprType_result, |
| 3884 | | front_result, |
| 3885 | | arg_result); |
| 3886 | | return TypeCheckerResult.compose(that, |
| 3887 | | fnApp_result.type(), |
| 3888 | | subtypeChecker, |
| 3889 | | fnApp_result); |
| 3890 | | } |
| 3891 | | |
| 3892 | | Iterable<Expr> rest = IterUtil.skipFirst(that.getExprs()); |
| 3893 | | List<MathItem> items = CollectUtil.makeList(IterUtil.map(rest, new Lambda<Expr,MathItem>(){ |
| | 3868 | // Just create a MathPrimary |
| | 3869 | Expr front = IterUtil.first(that.getExprs()); |
| | 3870 | |
| | 3871 | // If this juxt is actually a fn app, then rewrite to a fn app. |
| | 3872 | if (that.isFnApp()) { |
| | 3873 | // Make sure it is just two exprs. |
| | 3874 | if (that.getExprs().size() != 2) { |
| | 3875 | bug(String.format("TightJuxt denoted as function application but has %d (!= 2) exprs.", that.getExprs().size())); |
| | 3876 | } |
| | 3877 | Expr arg = that.getExprs().get(1); |
| | 3878 | _RewriteFnApp fnApp = new _RewriteFnApp(new Span(front.getSpan(), arg.getSpan()), |
| | 3879 | front, arg); |
| | 3880 | |
| | 3881 | // Simulate a TypeCheckerResult for the front, giving it a fresh arrow type. |
| | 3882 | Type freshArrow = NodeFactory.makeArrowType(new Span(), |
| | 3883 | NodeFactory.make_InferenceVarType(that.getSpan()), |
| | 3884 | NodeFactory.make_InferenceVarType(that.getSpan())); |
| | 3885 | TypeCheckerResult front_result = new TypeCheckerResult(front, freshArrow); |
| | 3886 | |
| | 3887 | // Type check the other nodes and recur on the fn app. |
| | 3888 | Option<TypeCheckerResult> exprType_result = this.recurOnOptionOfType(that.getExprType()); |
| | 3889 | TypeCheckerResult arg_result = arg.accept(this); |
| | 3890 | TypeCheckerResult fnApp_result = this.for_RewriteFnAppOnly(fnApp, |
| | 3891 | exprType_result, |
| | 3892 | front_result, |
| | 3893 | arg_result); |
| | 3894 | return TypeCheckerResult.compose(that, |
| | 3895 | fnApp_result.type(), |
| | 3896 | subtypeChecker, |
| | 3897 | fnApp_result); |
| | 3898 | } |
| | 3899 | |
| | 3900 | Iterable<Expr> rest = IterUtil.skipFirst(that.getExprs()); |
| | 3901 | List<MathItem> items = CollectUtil.makeList(IterUtil.map(rest, new Lambda<Expr,MathItem>(){ |