Skip to content

Commit c5d7e50

Browse files
Enforce module parameters to receive only module arguments
1 parent 4c24f08 commit c5d7e50

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,36 @@ extends Importer:
232232
term(rhs)
233233
case tree @ App(lhs, rhs) =>
234234
val sym = FlowSymbol("‹app-res›", nextUid)
235-
Term.App(term(lhs), term(rhs))(tree, sym)
235+
val lt = term(lhs)
236+
val rt = term(rhs)
237+
238+
// Check if module arguments match module parameters
239+
val args = rt match
240+
case Term.Tup(fields) => S(fields)
241+
case _ => N
242+
val params = lt.symbol
243+
.filter(_.isInstanceOf[BlockMemberSymbol])
244+
.flatMap(_.asInstanceOf[BlockMemberSymbol].trmTree)
245+
.filter(_.isInstanceOf[TermDef])
246+
.flatMap(_.asInstanceOf[TermDef].paramLists.headOption)
247+
for
248+
(args, params) <- (args zip params)
249+
(arg, param) <- (args zip params.fields)
250+
do
251+
val argMod = arg.flags.mod
252+
val paramMod = param match
253+
case Tree.TypeDef(Mod, _, _, _) => true
254+
case _ => false
255+
if argMod && !paramMod then
256+
raise:
257+
ErrorReport:
258+
msg"Module values can only be passed to module parameters." -> arg.toLoc :: Nil
259+
if !argMod && paramMod then
260+
raise:
261+
ErrorReport:
262+
msg"Module parameters can only receive module values." -> arg.toLoc :: Nil
263+
264+
Term.App(lt, rt)(tree, sym)
236265
case Sel(pre, nme) =>
237266
val preTrm = term(pre)
238267
val sym = resolveField(nme, preTrm.symbol, nme)

hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ f1(new C)
124124
// Error: module values can only be passed to module parameters.
125125
:e
126126
f1(M)
127+
//│ ╔══[ERROR] Module values can only be passed to module parameters.
128+
//│ ║ l.126: f1(M)
129+
//│ ╙── ^
127130
//│ Elaborated tree:
128131
//│ Blk:
129132
//│ stats = Nil
@@ -133,12 +136,11 @@ f1(M)
133136
//│ nme = Ident of "f1"
134137
//│ rhs = Tup of Ls of
135138
//│ Fld:
136-
//│ flags = ()
139+
//│ flags = (module)
137140
//│ value = Sel:
138141
//│ prefix = Ref of globalThis:block#1
139142
//│ nme = Ident of "M"
140143
//│ asc = N
141-
//│ FAILURE: Unexpected lack of type error
142144

143145

144146
// Good: m is a module parameter, therefore the module method foo can be called on m.
@@ -206,7 +208,7 @@ f2(M)
206208
//│ nme = Ident of "f2"
207209
//│ rhs = Tup of Ls of
208210
//│ Fld:
209-
//│ flags = ()
211+
//│ flags = (module)
210212
//│ value = Sel:
211213
//│ prefix = Ref of globalThis:block#1
212214
//│ nme = Ident of "M"
@@ -276,6 +278,9 @@ fun id[T](t: T): T = t
276278
// Error: Module values can only be passed to module parameters.
277279
:e
278280
id(IntMT)
281+
//│ ╔══[ERROR] Module values can only be passed to module parameters.
282+
//│ ║ l.280: id(IntMT)
283+
//│ ╙── ^^^^^
279284
//│ Elaborated tree:
280285
//│ Blk:
281286
//│ stats = Nil
@@ -285,12 +290,11 @@ id(IntMT)
285290
//│ nme = Ident of "id"
286291
//│ rhs = Tup of Ls of
287292
//│ Fld:
288-
//│ flags = ()
293+
//│ flags = (module)
289294
//│ value = Sel:
290295
//│ prefix = Ref of globalThis:block#9
291296
//│ nme = Ident of "IntMT"
292297
//│ asc = N
293-
//│ FAILURE: Unexpected lack of type error
294298

295299

296300
// Good: module parameters must have an explicit and concrete type.
@@ -330,7 +334,7 @@ idMod(IntMT)
330334
//│ nme = Ident of "idMod"
331335
//│ rhs = Tup of Ls of
332336
//│ Fld:
333-
//│ flags = ()
337+
//│ flags = (module)
334338
//│ value = Sel:
335339
//│ prefix = Ref of globalThis:block#9
336340
//│ nme = Ident of "IntMT"

0 commit comments

Comments
 (0)