diff --git a/src/Compiler/index.ts b/src/Compiler/index.ts
index ce37c4c..1988f59 100644
--- a/src/Compiler/index.ts
+++ b/src/Compiler/index.ts
@@ -1,7 +1,3 @@
-/**
- * @module edge
- */
-
 /*
 * edge
 *
@@ -12,10 +8,10 @@
 */
 
 import { EdgeError } from 'edge-error'
-import { Parser, EdgeBuffer, ParserToken, ParserTagToken } from 'edge-parser'
+import { Parser, EdgeBuffer } from 'edge-parser'
+import { Token, TagToken, utils as lexerUtils } from 'edge-lexer'
 
 import { CacheManager } from '../CacheManager'
-import { isBlockToken, getLineAndColumnForToken } from '../utils'
 import { LoaderContract, TagsContract, LoaderTemplate, CompilerContract } from '../Contracts'
 
 /**
@@ -27,33 +23,28 @@ import { LoaderContract, TagsContract, LoaderTemplate, CompilerContract } from '
  * the parsing process, it will recursively merge the layout sections.
  */
 export class Compiler implements CompilerContract {
-  private _cacheManager = new CacheManager(this._cache)
+  public cacheManager = new CacheManager(this.cache)
 
   constructor (
-    private _loader: LoaderContract,
-    private _tags: TagsContract,
-    private _cache: boolean = true,
+    private loader: LoaderContract,
+    private tags: TagsContract,
+    private cache: boolean = true,
   ) {}
 
   /**
    * Merges sections of base template and parent template tokens
    */
-  private _mergeSections (
-    base: ParserToken[],
-    extended: ParserToken[],
-    filename: string,
-    layoutPath: string,
-  ): ParserToken[] {
+  private mergeSections (base: Token[], extended: Token[]): Token[] {
     /**
      * Collection of all sections from the extended tokens
      */
-    const extendedSections: { [key: string]: ParserTagToken } = {}
+    const extendedSections: { [key: string]: TagToken } = {}
 
     /**
-     * Collection of extended set calls as top level nodes. Now since they are hanging
-     * up in the air, they will be hoisted like `var` statements in Javascript
+     * Collection of extended set calls as top level nodes. The set
+     * calls are hoisted just like `var` statements in Javascript.
      */
-    const extendedSetCalls: ParserTagToken[] = []
+    const extendedSetCalls: TagToken[] = []
 
     extended
       .forEach((node) => {
@@ -62,7 +53,7 @@ export class Compiler implements CompilerContract {
          * template
          */
         if (
-          isBlockToken(node, 'layout') ||
+          lexerUtils.isTag(node, 'layout') ||
           node.type === 'newline' ||
           (node.type === 'raw' && !node.value.trim())
         ) {
@@ -72,7 +63,7 @@ export class Compiler implements CompilerContract {
         /**
          * Collect parent template sections
          */
-        if (isBlockToken(node, 'section')) {
+        if (lexerUtils.isTag(node, 'section')) {
           extendedSections[node.properties.jsArg.trim()] = node
           return
         }
@@ -80,19 +71,20 @@ export class Compiler implements CompilerContract {
         /**
          * Collect set calls inside parent templates
          */
-        if (isBlockToken(node, 'set')) {
+        if (lexerUtils.isTag(node, 'set')) {
           extendedSetCalls.push(node)
           return
         }
 
         /**
-         * Everything else if not allowed as top level nodes
+         * Everything else is not allowed as top level nodes
          */
-        const [line, col] = getLineAndColumnForToken(node)
+        const [line, col] = lexerUtils.getLineAndColumn(node)
+
         throw new EdgeError(
-          `Template extending the layout can only define @sections as top level nodes`,
+          'Template extending a layout can only use "@section" or "@set" tags as top level nodes',
           'E_UNALLOWED_EXPRESSION',
-          { line, col, filename },
+          { line, col, filename: node.filename },
         )
       })
 
@@ -101,25 +93,21 @@ export class Compiler implements CompilerContract {
      */
     const finalNodes = base
       .map((node) => {
-        if (!isBlockToken(node, 'section')) {
-          node.filename = layoutPath
+        if (!lexerUtils.isTag(node, 'section')) {
           return node
         }
 
-        const extendedNode = extendedSections[node.properties.jsArg.trim()]
+        const sectionName = node.properties.jsArg.trim()
+        const extendedNode = extendedSections[sectionName]
         if (!extendedNode) {
-          node.filename = layoutPath
           return node
         }
 
         /**
          * Concat children when super was called
          */
-        if (extendedNode.children.length && isBlockToken(extendedNode.children[0], 'super')) {
-          extendedNode.children = node.children.map((child) => {
-            (child as ParserToken).filename = layoutPath
-            return child
-          }).concat(extendedNode.children)
+        if (extendedNode.children.length && lexerUtils.isTag(extendedNode.children[0], 'super')) {
+          extendedNode.children = node.children.concat(extendedNode.children)
         }
 
         return extendedNode
@@ -128,7 +116,7 @@ export class Compiler implements CompilerContract {
     /**
      * Set calls are hoisted to the top
      */
-    return ([] as ParserToken[]).concat(extendedSetCalls).concat(finalNodes)
+    return ([] as Token[]).concat(extendedSetCalls).concat(finalNodes)
   }
 
   /**
@@ -136,34 +124,17 @@ export class Compiler implements CompilerContract {
    * are checked for layouts and if layouts are used, their sections will be
    * merged together.
    */
-  private _templateContentToTokens (
-    content: string,
-    parser: Parser,
-    filename: string,
-  ): ParserToken[] {
-    let templateTokens = parser.generateLexerTokens(content)
+  private templateContentToTokens (content: string, parser: Parser): Token[] {
+    let templateTokens = parser.tokenize(content)
     const firstToken = templateTokens[0]
 
     /**
      * The `layout` is inbuilt feature from core, where we merge the layout
      * and parent template sections together
      */
-    if (isBlockToken(firstToken, 'layout')) {
+    if (lexerUtils.isTag(firstToken, 'layout')) {
       const layoutName = firstToken.properties.jsArg.replace(/'/g, '')
-
-      /**
-       * Making absolute path, so that lexer errors must point to the
-       * absolute file path
-       */
-      const absPath = this._loader.makePath(layoutName)
-      const layoutTokens = this.generateLexerTokens(absPath)
-
-      templateTokens = this._mergeSections(
-        layoutTokens,
-        templateTokens,
-        filename,
-        absPath,
-      )
+      templateTokens = this.mergeSections(this.tokenize(layoutName), templateTokens)
     }
 
     return templateTokens
@@ -171,18 +142,18 @@ export class Compiler implements CompilerContract {
 
   /**
    * Converts the template content to an [array of lexer tokens]. The method is
-   * same as the `parser.generateLexerTokens`, plus it will handle the layouts
-   * and it's sections.
+   * same as the `parser.tokenize`, but it also handles layouts natively.
    *
    * ```
-   * compiler.generateLexerTokens('<template-path>')
+   * compiler.tokenize('<template-path>')
    * ```
    */
-  public generateLexerTokens (templatePath: string): ParserToken[] {
-    const { template } = this._loader.resolve(templatePath, false)
+  public tokenize (templatePath: string): Token[] {
+    const absPath = this.loader.makePath(templatePath)
+    const { template } = this.loader.resolve(absPath, false)
 
-    const parser = new Parser(this._tags, { filename: templatePath })
-    return this._templateContentToTokens(template, parser, templatePath)
+    const parser = new Parser(this.tags, { filename: absPath })
+    return this.templateContentToTokens(template, parser)
   }
 
   /**
@@ -207,19 +178,19 @@ export class Compiler implements CompilerContract {
    * ```
    */
   public compile (templatePath: string, inline: boolean): LoaderTemplate {
-    const absPath = this._loader.makePath(templatePath)
+    const absPath = this.loader.makePath(templatePath)
 
     /**
      * If template is in the cache, then return it without
      * further processing
      */
-    const cachedResponse = this._cacheManager.get(absPath)
+    const cachedResponse = this.cacheManager.get(absPath)
     if (cachedResponse) {
       return cachedResponse
     }
 
     /**
-     * Do not load presenter in inline mode
+     * Do not return presenter in inline mode
      */
     const loadPresenter = !inline
 
@@ -232,32 +203,32 @@ export class Compiler implements CompilerContract {
     /**
      * Get a new instance of the parser.
      */
-    const parser = new Parser(this._tags, { filename: absPath })
+    const parser = new Parser(this.tags, { filename: absPath })
 
     /**
-     * Resolve the template and Presenter using the given loader
+     * Resolve the template and Presenter using the given loader. We always
+     * load the presenter but don't return it when `loadPresenter = false`.
      */
-    const { template, Presenter } = this._loader.resolve(absPath, loadPresenter)
+    const { template, Presenter } = this.loader.resolve(absPath, true)
 
     /**
      * Convert template to AST. The AST will have the layout actions merged (if layout)
      * is used.
      */
-    const templateTokens = this._templateContentToTokens(template, parser, absPath)
+    const templateTokens = this.templateContentToTokens(template, parser)
 
     /**
      * Finally process the ast
      */
-    const buffer = new EdgeBuffer()
-    buffer.writeStatement(`ctx.set('$filename', '${templatePath.replace(/\.edge$/, '')}.edge');`)
-    templateTokens.forEach((token) => parser.processLexerToken(token, buffer))
+    const buffer = new EdgeBuffer(absPath, wrapAsFunction)
+    templateTokens.forEach((token) => parser.processToken(token, buffer))
 
     const payload = {
-      template: buffer.flush(wrapAsFunction),
+      template: buffer.flush(),
       Presenter,
     }
 
-    this._cacheManager.set(absPath, payload)
-    return payload
+    this.cacheManager.set(absPath, payload)
+    return loadPresenter ? payload : { template: payload.template }
   }
 }
diff --git a/test/compiler.spec.ts b/test/compiler.spec.ts
index 688fbc6..5bd949f 100644
--- a/test/compiler.spec.ts
+++ b/test/compiler.spec.ts
@@ -9,16 +9,23 @@
 
 import test from 'japa'
 import { join } from 'path'
+import dedent from 'dedent-js'
 import { Filesystem } from '@poppinss/dev-utils'
+import { TagTypes, MustacheTypes } from 'edge-lexer'
 
 import { Loader } from '../src/Loader'
+import { Context } from '../src/Context'
 import { Compiler } from '../src/Compiler'
+import { layoutTag } from '../src/Tags/Layout'
+import { sectionTag } from '../src/Tags/Section'
+import { setTag } from '../src/Tags/Set'
+import './assert-extend'
 
 const tags = {}
 
 const fs = new Filesystem(join(__dirname, 'views'))
 
-test.group('Compiler', (group) => {
+test.group('Compiler | Cache', (group) => {
   group.afterEach(async () => {
     await fs.cleanup()
   })
@@ -30,16 +37,23 @@ test.group('Compiler', (group) => {
     loader.mount('default', fs.basePath)
 
     const compiler = new Compiler(loader, tags)
-    assert.equal(compiler.compile('foo', false).template, `(function (template, ctx) {
-  let out = '';
-  ctx.set('$filename', 'foo.edge');
-  out += 'Hello ';
-  out += \`\${ctx.escape(ctx.resolve('username'))}\`;
-  return out;
-})(template, ctx)`)
+    const { template } = compiler.compile('foo', false)
+
+    assert.stringEqual(template, dedent`return (function (template, ctx) {
+    let out = '';
+    ctx.$lineNumber = 1;
+    ctx.$filename = '${join(fs.basePath, 'foo.edge')}';
+    try {
+    out += 'Hello ';
+    out += \`\${ctx.escape(ctx.resolve('username'))}\`;
+    } catch (error) {
+    ctx.reThrow(error);
+    }
+    return out;
+    })(template, ctx)`)
   })
 
-  test('save template to cache when is turned on', async (assert) => {
+  test('save template to cache when caching is turned on', async (assert) => {
     await fs.add('foo.edge', 'Hello {{ username }}')
 
     const loader = new Loader()
@@ -48,7 +62,7 @@ test.group('Compiler', (group) => {
     const compiler = new Compiler(loader, tags, true)
     assert.equal(
       compiler.compile('foo', false),
-      compiler['_cacheManager'].get(join(fs.basePath, 'foo.edge')),
+      compiler.cacheManager.get(join(fs.basePath, 'foo.edge')),
     )
   })
 
@@ -62,7 +76,7 @@ test.group('Compiler', (group) => {
     const compiler = new Compiler(loader, tags, true)
     compiler.compile('foo', false)
     assert.equal(
-      compiler['_cacheManager'].get(join(fs.basePath, 'foo.edge'))!.Presenter!['name'],
+      compiler.cacheManager.get(join(fs.basePath, 'foo.edge'))!.Presenter!['name'],
       'Foo',
     )
   })
@@ -75,31 +89,493 @@ test.group('Compiler', (group) => {
 
     const compiler = new Compiler(loader, tags, false)
     compiler.compile('foo', false)
-    assert.isUndefined(compiler['_cacheManager'].get(join(fs.basePath, 'foo.edge')))
+    assert.isUndefined(compiler.cacheManager.get(join(fs.basePath, 'foo.edge')))
   })
 
-  test('do not wrap inline templates to a function', async (assert) => {
+  test('do not load presenter for inline templates', async (assert) => {
     await fs.add('foo.edge', 'Hello {{ username }}')
+    await fs.add('foo.presenter.js', '')
+
     const loader = new Loader()
     loader.mount('default', fs.basePath)
 
     const compiler = new Compiler(loader, tags)
-    assert.equal(compiler.compile('foo', true).template, `
-  let out = '';
-  ctx.set('$filename', 'foo.edge');
-  out += 'Hello ';
-  out += \`\${ctx.escape(ctx.resolve('username'))}\`;
-  return out;`)
+    assert.isUndefined(compiler.compile('foo', true).Presenter)
+    assert.isDefined(compiler.compile('foo', false).Presenter)
   })
+})
 
-  test('do not load presenter for inline templates', async (assert) => {
-    await fs.add('foo.edge', 'Hello {{ username }}')
-    await fs.add('foo.presenter.js', '')
+test.group('Compiler | Tokenize', (group) => {
+  group.afterEach(async () => {
+    await fs.cleanup()
+  })
+
+  test('during tokenize, merge @section tags of a given layout', async (assert) => {
+    await fs.add('master.edge', dedent`
+    Master page
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      Hello world
+    @endsection
+    `)
 
     const loader = new Loader()
     loader.mount('default', fs.basePath)
 
-    const compiler = new Compiler(loader, tags)
-    assert.isUndefined(compiler.compile('foo', true).Presenter)
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    assert.deepEqual(compiler.tokenize('index.edge'), [
+      {
+        type: 'raw' as const,
+        value: 'Master page',
+        line: 1,
+        filename: join(fs.basePath, 'master.edge'),
+      },
+      {
+        type: 'newline' as const,
+        line: 1,
+        filename: join(fs.basePath, 'master.edge'),
+      },
+      {
+        type: TagTypes.TAG,
+        filename: join(fs.basePath, 'index.edge'),
+        properties: { name: 'section', jsArg: `'content'`, selfclosed: false },
+        loc: {
+          start: { line: 2, col: 9 },
+          end: { line: 2, col: 19 },
+        },
+        children: [
+          {
+            type: 'raw' as const,
+            value: '  Hello world',
+            line: 3,
+            filename: join(fs.basePath, 'index.edge'),
+          },
+        ],
+      },
+    ])
+  })
+
+  test('during tokenize, merge @set tags of a given layout', async (assert) => {
+    await fs.add('master.edge', dedent`
+    Master page
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @set('username', 'virk')
+    @section('content')
+      Hello world
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+      set: setTag,
+    })
+
+    assert.deepEqual(compiler.tokenize('index.edge'), [
+      {
+        type: TagTypes.TAG,
+        filename: join(fs.basePath, 'index.edge'),
+        properties: { name: 'set', jsArg: `'username', 'virk'`, selfclosed: false },
+        loc: {
+          start: { line: 2, col: 5 },
+          end: { line: 2, col: 24 },
+        },
+        children: [],
+      },
+      {
+        type: 'raw' as const,
+        value: 'Master page',
+        line: 1,
+        filename: join(fs.basePath, 'master.edge'),
+      },
+      {
+        type: 'newline' as const,
+        line: 1,
+        filename: join(fs.basePath, 'master.edge'),
+      },
+      {
+        type: TagTypes.TAG,
+        filename: join(fs.basePath, 'index.edge'),
+        properties: { name: 'section', jsArg: `'content'`, selfclosed: false },
+        loc: {
+          start: { line: 3, col: 9 },
+          end: { line: 3, col: 19 },
+        },
+        children: [
+          {
+            type: 'raw' as const,
+            value: '  Hello world',
+            line: 4,
+            filename: join(fs.basePath, 'index.edge'),
+          },
+        ],
+      },
+    ])
+  })
+
+  test('ensure template extending layout can only use section or set tags', async (assert) => {
+    assert.plan(4)
+
+    await fs.add('master.edge', dedent`
+    Master page
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    Hello world
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    try {
+      compiler.tokenize('index.edge')
+    } catch (error) {
+      assert.equal(
+        error.message,
+        'Template extending a layout can only use "@section" or "@set" tags as top level nodes',
+      )
+      assert.equal(error.filename, join(fs.basePath, 'index.edge'))
+      assert.equal(error.line, 2)
+      assert.equal(error.col, 0)
+    }
+  })
+
+  test('during tokenize, merge @section tags of a nested layouts', async (assert) => {
+    await fs.add('super-master.edge', dedent`
+    Master page
+    @!section('header')
+    @!section('content')
+    `)
+
+    await fs.add('master.edge', dedent`
+    @layout('super-master')
+    @section('header')
+      This is header
+    @endsection
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      This is content
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    assert.deepEqual(compiler.tokenize('index.edge'), [
+      {
+        type: 'raw' as const,
+        value: 'Master page',
+        line: 1,
+        filename: join(fs.basePath, 'super-master.edge'),
+      },
+      {
+        type: 'newline' as const,
+        line: 1,
+        filename: join(fs.basePath, 'super-master.edge'),
+      },
+      {
+        type: TagTypes.TAG,
+        filename: join(fs.basePath, 'master.edge'),
+        properties: { name: 'section', jsArg: `'header'`, selfclosed: false },
+        loc: {
+          start: { line: 2, col: 9 },
+          end: { line: 2, col: 18 },
+        },
+        children: [
+          {
+            type: 'raw' as const,
+            value: '  This is header',
+            line: 3,
+            filename: join(fs.basePath, 'master.edge'),
+          },
+        ],
+      },
+      {
+        type: TagTypes.TAG,
+        filename: join(fs.basePath, 'index.edge'),
+        properties: { name: 'section', jsArg: `'content'`, selfclosed: false },
+        loc: {
+          start: { line: 2, col: 9 },
+          end: { line: 2, col: 19 },
+        },
+        children: [
+          {
+            type: 'raw' as const,
+            value: '  This is content',
+            line: 3,
+            filename: join(fs.basePath, 'index.edge'),
+          },
+        ],
+      },
+    ])
+  })
+
+  test('layout tokens must point to its own filename', async (assert) => {
+    await fs.add('master.edge', dedent`
+    {{ username }}
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      Hello world
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    assert.deepEqual(compiler.tokenize('index.edge'), [
+      {
+        type: MustacheTypes.MUSTACHE,
+        filename: join(fs.basePath, 'master.edge'),
+        loc: {
+          start: { line: 1, col: 2 },
+          end: { line: 1, col: 14 },
+        },
+        properties: { jsArg: ` username ` },
+      },
+      {
+        type: 'newline' as const,
+        line: 1,
+        filename: join(fs.basePath, 'master.edge'),
+      },
+      {
+        type: TagTypes.TAG,
+        filename: join(fs.basePath, 'index.edge'),
+        properties: { name: 'section', jsArg: `'content'`, selfclosed: false },
+        loc: {
+          start: { line: 2, col: 9 },
+          end: { line: 2, col: 19 },
+        },
+        children: [
+          {
+            type: 'raw' as const,
+            value: '  Hello world',
+            line: 3,
+            filename: join(fs.basePath, 'index.edge'),
+          },
+        ],
+      },
+    ])
+  })
+})
+
+test.group('Compiler | Compile', (group) => {
+  group.afterEach(async () => {
+    await fs.cleanup()
+  })
+
+  test('compile template with layouts', async (assert) => {
+    await fs.add('master.edge', dedent`
+    {{ username }}
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      {{ content }}
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    assert.stringEqual(compiler.compile('index.edge', false).template, dedent`
+    return (function (template, ctx) {
+    let out = '';
+    ctx.$lineNumber = 1;
+    ctx.$filename = '${join(fs.basePath, 'index.edge')}';
+    try {
+    ctx.$filename = '${join(fs.basePath, 'master.edge')}';
+    out += \`\${ctx.escape(ctx.resolve('username'))}\`;
+    out += '\\n';
+    out += '  ';
+    ctx.$filename = '${join(fs.basePath, 'index.edge')}';
+    ctx.$lineNumber = 3;
+    out += \`\${ctx.escape(ctx.resolve('content'))}\`;
+    } catch (error) {
+    ctx.reThrow(error);
+    }
+    return out;
+    })(template, ctx)
+    `)
+  })
+
+  test('compile errors inside layout must point to the right file', async (assert) => {
+    assert.plan(3)
+
+    await fs.add('master.edge', dedent`
+    {{ user name }}
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      {{ content }}
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    try {
+      compiler.compile('index.edge', false)
+    } catch (error) {
+      assert.equal(error.filename, join(fs.basePath, 'master.edge'))
+      assert.equal(error.line, 1)
+      assert.equal(error.col, 8)
+    }
+  })
+
+  test('compile errors parent template must point to the right file', async (assert) => {
+    assert.plan(3)
+
+    await fs.add('master.edge', dedent`
+    {{ username }}
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      {{ con tent }}
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    try {
+      compiler.compile('index.edge', false)
+    } catch (error) {
+      assert.equal(error.filename, join(fs.basePath, 'index.edge'))
+      assert.equal(error.line, 3)
+      assert.equal(error.col, 9)
+    }
+  })
+
+  test('runtime errors inside layout must point to the right file', async (assert) => {
+    assert.plan(4)
+
+    await fs.add('master.edge', dedent`
+      {{ getUserName() }}
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      {{ content }}
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    try {
+      new Function('template', 'ctx', compiler.compile('index.edge', false).template)(
+        {},
+        new Context({ state: {} }, {}),
+      )
+    } catch (error) {
+      assert.equal(error.message, 'getUserName is not a function')
+      assert.equal(error.filename, join(fs.basePath, 'master.edge'))
+      assert.equal(error.line, 1)
+      assert.equal(error.col, 0)
+    }
+  })
+
+  test('runtime errors inside parent template must point to the right file', async (assert) => {
+    assert.plan(4)
+
+    await fs.add('master.edge', dedent`
+    {{ username }}
+    @!section('content')
+    `)
+
+    await fs.add('index.edge', dedent`
+    @layout('master')
+    @section('content')
+      {{ getContent() }}
+    @endsection
+    `)
+
+    const loader = new Loader()
+    loader.mount('default', fs.basePath)
+
+    const compiler = new Compiler(loader, {
+      section: sectionTag,
+      layout: layoutTag,
+    })
+
+    try {
+      const fn = new Function('template', 'ctx', compiler.compile('index.edge', false).template)
+      fn({}, new Context({ state: {} }, {}))
+    } catch (error) {
+      assert.equal(error.message, 'getContent is not a function')
+      assert.equal(error.filename, join(fs.basePath, 'index.edge'))
+      assert.equal(error.line, 3)
+      assert.equal(error.col, 0)
+    }
   })
 })